Source: mixins/ol-map-events.js

/**
 * @desc A mixin object containing methods related to map events
 * @module MapEventssMixin
 */
import { toLonLat } from 'ol/proj';
import Geolocation from "ol/Geolocation";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import { MapEditingMixin } from './ol-map-editing';
export const MapEventsMixin = {
    mixins: [MapEditingMixin],
    data() {
        return {
        }
    },
    methods: {

        /**
         * Creates event listeners for various map events.
         */
        createEvents() {

            this.map.on("error", e => {
                this.showError(e);
            });

            this.map.on("rendercomplete", e => {
                this.$store.working = false;
            });

            this.map.on('pointermove', e => {
                //if (this.moveTimeout) clearTimeout(this.moveTimeout);
                //this.moveTimeout = setTimeout(() => {
                const pixel = this.map.getEventPixel(e.originalEvent);
                const hit = this.map.hasFeatureAtPixel(pixel);
                this.cursorXY = this.map.getCoordinateFromPixel(pixel);
                this.cursorPixel = pixel;
                this.$refs.map.style.cursor = hit ? 'pointer' : '';
                this.cursorPosition = toLonLat(this.cursorXY, this.projection);
                let value = null, name = null;
                this.infoTip.style.visibility = 'hidden';
                //if (this.tiffLayer.getSource() != null) {
                if (this.selectedTitle != null) {
                    let d = this.tiffLayer.getData(pixel);
                    if (d) {
                        value = this.rescale(d[0]).toFixed(this.selectedTitle.decimals);
                    }
                }
                if (hit) {
                    for (let f of this.map.getFeaturesAtPixel(e.pixel)) {
                        while (f.values_.features) f = f.values_.features[0];
                        name = f.get("name");
                        if (name == "positionFeature" || name == "accuracyFeature") {
                            //this.$refs.map.style.cursor = '';
                            name = null;
                            continue;
                        }
                    }
                }
                if (name || value) {
                    this.$refs.map.style.cursor = 'pointer';
                    this.infoTip.style.left = (e.pixel[0] + 10) + 'px';
                    this.infoTip.style.top = (e.pixel[1] - 10) + 'px';
                    this.infoTip.innerText = (name ?? "") + (value ? " " : "") + (value ?? "");
                    this.infoTip.style.visibility = 'visible';
                } else {
                    this.infoTip.style.visibility = 'hidden';
                    this.$refs.map.style.cursor = '';   
                }
                //}, 100);
            });

            this.map.getView().on('change:resolution', (e) => {
                this.zoom = this.map.getView().getZoom();
                this.extent = this.map.getView().calculateExtent(this.map.getSize());
            });

            //this.map.on('contextmenu', this.findFeature);
            
            this.map.on('moveend', (e) => {
                this.zoom = this.map.getView().getZoom();
                if (this.pointLayer && this.pointLayer.getSource()) {
                    this.pointLayer.getSource().changed();
                }
                this.extent = this.map.getView().calculateExtent(this.map.getSize());
                this.center = toLonLat(this.map.getView().getCenter(), this.projection);
                this.rotation = this.map.getView().getRotation();
                if (this.crosshair && this.crosshairOverlay) {
                    this.crosshairOverlay.setPosition(this.map.getView().getCenter());
                }
                this.setBoundariesLayer();
            });
            
            this.modify.on('modifystart', (e) => {
                let f = e.features.getArray()[0];
                let c = f.clone();
                c.set("orig_id", f.getId());
                this.editStack.push(c);
            });

            this.modify.on('modifyend', (e) => {
                let f = e.features.getArray()[0];
                this.saveFeature(f, this.format, this.projection, this.projectionForSave);
            }); 

            // this.select.on("select", e => {
            //     if (this.drawVertexByVertex) return;
            //     let f = e.selected[0];
            //     while (f.values_ && f.values_.features) f = f.values_.features[0];
            //     this.showFeatureInfo(f);
            // });

            this.map.on('singleclick', (e) => {
                //this.$refs.clickMenu.hide();
                if (this.drawVertexByVertex) {
                    window.dispatchEvent(new CustomEvent('vertexAdded', { detail: { coords: this.map.getCoordinateFromPixel(e.pixel) } }));
                    return;
                }
                if (this.activeAction != null) return;
                //this.select.getFeatures().clear();
                for (let f of this.map.getFeaturesAtPixel(e.pixel)) {
                    while (f.values_.features) f = f.values_.features[0];
                    this.showFeatureInfo(f);
                    return;
                }
                this.selectedFeature = null;
            });
        },	

        /**
         * Shows the properties of a feature.
         * @param {Feature} f The feature to show properties for.
         */
        showFeatureInfo(f) {
            this.$refs.clickMenu.hide();
            // this.$refs.popup.hide();
            let name = f.get("name");
            if (name == "positionFeature" || name == "accuracyFeature") {
                //this.select.getFeatures().clear();
                return;
            }
            this.infoTip.style.visibility = 'hidden';
            this.selectedFeature = f;

            if (f.get("custom_geometry_id") != null) {
                this.editProps();
            } else {
                this.showProps();
            }
        },
        
        /**
         * Sets up geolocation functionality.
         */
        createGeolocation() {
            let self = this;

            this.geolocation = new Geolocation({
                trackingOptions: {
                    enableHighAccuracy: true,
                },
                projection: this.projection,
            });
            this.geolocation.setTracking(true);

            this.accuracyFeature = new Feature();
            this.accuracyFeature.set("name", "accuracyFeature");

            this.geolocation.on('change:accuracyGeometry', function () {
                self.accuracyFeature.setGeometry(self.geolocation.getAccuracyGeometry());
            });
            
            let pos = this.$store.position ?? [0,0];
            let pointGeometry = new Point(pos);
            this.positionFeature = new Feature({geometry: pointGeometry});
            this.positionFeature.setStyle(this.positionStyle);
            this.positionFeature.set("name", "positionFeature");

            this.geolocation.on('change:position', function () {
                self.positionFeature.getGeometry().setCoordinates(self.geolocation.getPosition());
                self.$store.position = self.geolocation.getPosition();
            });

            this.geolocation.on('error', function (error) {
                alert(error.message);
            });

       }
    },
}