Source: specific/mixins/ol-map-events.js

/**
 * @desc A mixin object containing methods related to map events
 * @module MapEventssMixin
 */
import { get, 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: {

        /**
         * Returns tiffLayer and selectedTitle based on the pixel value.
         * @param {*} pixel 
         * @returns {Object} An object containing the selectedTitle and tiffLayer.
         */
        getActiveTiffLayer(pixel) {
            const mapSize = this.map.getSize();

            let selectedTitle = this.selectedTitle;
            let tiffLayer = this.tiffLayer;

            if (this.altSelectedCatalog && pixel[0] > mapSize[0] * this.compare) {
                selectedTitle = this.altSelectedTitle;
                tiffLayer = this.altTiffLayer;
            }
            return { selectedTitle, tiffLayer };
        },

        /**
         * Returns the value at the pixel location.
         * @param {*} pixel
         * @returns {String} The value at the pixel location.
         */
        getValueAtPixel(pixel) {
            let r = this.getActiveTiffLayer(pixel);
            let selectedTitle = r.selectedTitle;
            let tiffLayer = r.tiffLayer;

            let d = tiffLayer.getData(pixel);
            
            let value = null;

            if (d && d[0] != selectedTitle.no_data && d[0] != 0) {
                if (selectedTitle.numerical) {
                    value = this.rescale(d[0], selectedTitle.scale_factor).toFixed(selectedTitle.decimals);
                } else {
                    if (selectedTitle.description) value = selectedTitle.description[d[0]].name;
                }
            }
            return value;
        },

        /**
         * 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 => {
                
                const pixel = this.map.getEventPixel(e.originalEvent);
                const hit = this.map.hasFeatureAtPixel(pixel);
                this.cursorXY = this.map.getCoordinateFromPixel(pixel);
                this.cursorPixel = pixel;
                this.cursorPosition = toLonLat(this.cursorXY, this.projection);
                
                let value = null, name = null;
                this.infoTip.style.visibility = 'hidden';

                if (this.selectedTitle != null) {          
                    value = this.getValueAtPixel(pixel);
                }

                if (hit) {
                    for (let f of this.map.getFeaturesAtPixel(e.pixel)) {
                        while (f.values_.features) f = f.values_.features[0];
                        name = f.get("name") ?? f.get("Name");
                        if (name == "positionFeature" || name == "accuracyFeature") {
                            name = null;
                            continue;
                        }
                        value = f.get("value") ?? f.get("description") ?? value;
                        break;
                    }
                }

                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';
                    let text = (name ?? "") + (value ? " " : "") + (value ?? "");
                    this.infoTip.innerText = text;
                    this.infoTip.style.visibility = 'visible';
                } else {
                    this.infoTip.style.visibility = 'hidden';
                    this.$refs.map.style.cursor = '';   
                }

            });
           
            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.setShapeLayer();
                this.setBoundariesLayer();
                this.setCustomRestrictedLayer();
            });
            
            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.map.on('singleclick', (e) => {
    
                if (this.drawVertexByVertex) {
                    window.dispatchEvent(new CustomEvent('vertexAdded', { detail: { coords: this.map.getCoordinateFromPixel(e.pixel) } }));
                    return;
                }

                for (let f of this.map.getFeaturesAtPixel(e.pixel)) {
                    while (f.values_.features) f = f.values_.features[0];
                    let name = f.get("name") ?? f.get("Name");
                    if (name != "positionFeature" && name != "accuracyFeature") {
                        this.infoTip.style.visibility = 'hidden';
                        this.selectedFeature = f;
                        this.editProps();
                        return;
                    }
                }

                if (this.selectedTitle) {
                    //create feature at clicked location
                    let feature = new Feature({
                        geometry: new Point(this.map.getCoordinateFromPixel(e.pixel)),
                    });
                    feature.set("name", "Point");
                    feature.set("x", this.map.getCoordinateFromPixel(e.pixel)[0]);
                    feature.set("y", this.map.getCoordinateFromPixel(e.pixel)[1]);
                    feature.set ("value", this.getValueAtPixel(e.pixel));
                    this.selectedFeature = feature;
                    this.editProps();
                }
            });
        },	
       
        /**
         * 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);
            });

       }
    },
}