Source: components/ol-map-popup-obsolete.vue

<template>
    <div id="popup" class="ol-map-popup max-width">
        <a href="#" id="popup-closer" class="ol-map-popup-closer"></a>
        <div id="popup-content">
            <div class="text-weight-bold" v-html="title ?? $t('Unnamed feature')" />
            <div v-if="featureProperties">
                <div v-for="o of featureProperties" :key="o.key">
                    <div v-html="`${o.key} : ${o.value ?? ''}`" />
                </div>
            </div>
            <div>
                <q-btn flat dense @click="showHistory">{{ $t('History') }}</q-btn>
            </div>
            <div v-if="hasFeatureStatsButton">
                <q-btn flat dense @click="showFeatureStats">{{ $t('Statistics') }}</q-btn>
            </div>
            <a v-if="options && options.api2Link" @click="$emit('children', feature)">{{ options.api2Link }}</a>
        </div>
    </div>
</template>
<script>
/**
 * Popup component for displaying properties of a map feature.
 * 
 * @component
 * @name OlMapPopup
 * @example
 * <OlMapPopup />
 */

import Overlay from "ol/Overlay"
export default {
    name: "OlMapPopup",
    props: {
        options: { type: Object },
    },
    data() {
        return {
            title: null,
            map: null,
            overlay: null,
            container: null,
            feature: null,
            featureProperties: null,
            parent: null
        }
    },
    /**
     * Initializes the popup.
     */
    async mounted() {
        await this.$nextTick();
        let closer = document.getElementById('popup-closer');
        this.container = document.getElementById('popup');
        closer.onclick = (e) => {
            this.hide();
            closer.blur();
            return false;
        };
    },
    methods: {
        showHistory() {
            this.parent.showHistory();
        },
        showFeatureStats() {
            this.parent.showFeatureStats();
        },

        /**
         * Checks should we display feature stats button
         * 
         * @returns {boolean} True if the feature has a history button, false otherwise.
         */
        hasFeatureStatsButton() {
            return this.parent && this.parent.selectedTitle && this.feature.get("custom_geometry_id") && this.feature.getGeometry().getType() != "Point";
        },

        /**
         * Hides the popup.
         */
        hide() {
            if (this.overlay) this.overlay.setPosition(undefined);
            this.$mitt.off('escKeyPressed');
        },

        /**
         * Shows the popup.
         * 
         * @param {Object} map - The map to show the popup on.
         * @param {string} title - The title of the popup.
         * @param {Array} coordinates - The coordinates of the popup.
         * @param {Object} feature - The feature to show the popup for.
         * @param {Object} additionalProps - Additional properties to show in the popup.
         */
        show(map, title, coordinates, feature, parent, additionalProps) {
            this.$mitt.on('escKeyPressed', () => {
                this.hide();
            });
            this.title = title;
            this.map = map;
            this.feature = feature;
            this.featureProperties = [];
            this.parent = parent;
            let skipProperty = ["color_code", "geometry", "geometry_type_id", "Name", "name"];

            // workaround: feature.getProperties() does not work in v-for
            for (let key in this.feature.getProperties()) {
                // if key is not in skipProperty
                if (!skipProperty.find(x => x == key)) {
                    let value = this.feature.get(key);
                    if (value instanceof Array) {
                        for (let v of value) {
                            if (v.name && v.name.toLowerCase() == "name") {
                                this.title = v.value;
                            } else if (v.name != null) {
                                let prop = this.$store.catalogs.properties.find(x => x.id == v.property_id);
                                if (prop == null || !prop.indicator_id || prop.numerical) {
                                    this.featureProperties.push({ key: v.name, value: this.formatValue(v.value) });
                                } else {
                                    this.featureProperties.push({ key: v.name, value: this.$store.catalogs.descriptions.find(x => x.indicator_id == prop.indicator_id && x.value == v.value).label });
                                }
                            }
                        }
                    } else if (value != null) {
                        this.featureProperties.push({ key: key, value: this.formatValue(value) });
                    }
                }
            }
            for (let key in additionalProps) {
                this.featureProperties.push({ key: key, value: additionalProps[key] });
            }

            if (!this.overlay) {
                this.overlay = new Overlay({
                    zIndex: 9999,
                    element: this.container,
                    autoPan: {
                        animation: {
                            duration: 250,
                        },
                    },
                    stopEvent: true,
                    className: 'ol-map-popup',
                });
                this.map.addOverlay(this.overlay);
                this.container.style.visibility = 'visible';
                this.overlay.getElement().addEventListener('click', (event) => {
                    event.stopPropagation();
                });
                this.overlay.getElement().addEventListener('contextmenu', (event) => {
                    event.stopPropagation();
                });
            }
            this.overlay.setPosition(coordinates);
            this.$store.menuDisabled = true;
        }
    }
}
</script>

<style scoped>
.ol-map-popup {
    position: absolute;
    background-color: white;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
    /* padding: 15px; */
    border-radius: 5px;
    border: 1px solid #cccccc;
    bottom: 12px;
    left: -50px;
    padding: 5px 25px 5px 5px;
    visibility: hidden;
    white-space: nowrap;
    max-width: 300px;
}

.ol-map-popup:after,
.ol-map-popup:before {
    top: 100%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}

.ol-map-popup:after {
    border-top-color: white;
    border-width: 10px;
    left: 48px;
    margin-left: -10px;
}

.ol-map-popup:before {
    border-top-color: #cccccc;
    border-width: 11px;
    left: 48px;
    margin-left: -11px;
}

.ol-map-popup-closer {
    text-decoration: none;
    position: absolute;
    top: 2px;
    right: 5px;
    z-index: 999;
}

.ol-map-popup-closer:after {
    content: "✖";
}
</style>