aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2025-06-12 20:04:03 +0200
committerGuilhem Moulin <guilhem@fripost.org>2025-06-15 02:30:57 +0200
commit4a088f5acfa747da8461493b98a2bcb6b1a47886 (patch)
tree1cf0a8cc1f81621dfb34687c0d08a1ec1a75d171
parent5a0ab32b06fe14d83e01b8f94f5f3030a18d24ab (diff)
Refactor popover handling.
In particular, make the definition object hierarchical and rename its fields.
-rw-r--r--main.js50
-rw-r--r--src/popover.js784
2 files changed, 437 insertions, 397 deletions
diff --git a/main.js b/main.js
index aa58199..0055b88 100644
--- a/main.js
+++ b/main.js
@@ -46,10 +46,10 @@ import proj4 from 'proj4';
import { get as getProjection } from 'ol/proj.js';
import { register as registerProjection } from 'ol/proj/proj4.js';
-import { Modal, Popover } from 'bootstrap';
+import { Modal } from 'bootstrap';
import { layers } from './src/layers.js';
-import { popover } from './src/popover.js';
+import { initPopupOverLay, initPopover, disposePopover } from './src/popover.js';
import './src/style.css';
proj4.defs('EPSG:3006', '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs');
@@ -275,8 +275,6 @@ const map = new Map({
target: document.getElementById('map'),
});
-const popup = document.getElementById('popup');
-
/* move the control container to the viewport */
const container = document.getElementById('map-control-container');
(function() {
@@ -459,9 +457,8 @@ if (window.location === window.parent.location) {
map.addControl(control);
control.addEventListener('enterfullscreen', function() {
- featureOverlayLayer.setVisible(false);
/* dispose popover as entering fullscreen messes up its position */
- Popover.getInstance(popup)?.dispose();
+ disposePopover()
const btn = control.element.getElementsByTagName('button')[0];
btn.classList.replace(classInactive, classActive);
@@ -475,9 +472,8 @@ if (window.location === window.parent.location) {
}
})
control.addEventListener('leavefullscreen', function() {
- featureOverlayLayer.setVisible(false);
/* dispose popover as is might overflow the viewport */
- Popover.getInstance(popup)?.dispose();
+ disposePopover();
const btn = control.element.getElementsByTagName('button')[0];
btn.classList.replace(classActive, classInactive);
@@ -780,8 +776,7 @@ if (window.location === window.parent.location) {
container.setAttribute('aria-hidden', 'false');
view.on('change', function() {
- featureOverlayLayer.setVisible(false);
- Popover.getInstance(popup)?.dispose();
+ disposePopover();
const coordinates = view.getCenter();
const searchParams = new URLSearchParams(location.hash.substring(1));
@@ -1202,7 +1197,7 @@ const styles = (function() {
}, {});
})();
-const [mapLayers, featureOverlayLayer] = (function() {
+const mapLayers = (function() {
const baseurl = '/';
const xyz = '/{z}/{x}/{y}.pbf';
const tileGrid = createXYZ({
@@ -1299,31 +1294,7 @@ const [mapLayers, featureOverlayLayer] = (function() {
map.addLayer(ret[k]);
});
- return [
- ret,
-
- /* We use a vector tile layer for featureOverlayLayer instead of a simple
- * vector layer overlay, since we don't want to clip selected geometries at
- * tile boundaries. It sounds overkill to load an entire tile layer to
- * display a single feature, but this shouldn't cause much overhead in
- * practice (the tiles are most likely cached already). */
- new VectorTileLayer({
- source: new VectorTile({
- urls: [],
- format: new MVT(),
- projection: projection,
- wrapX: false,
- transition: 0,
- tileGrid: tileGrid,
- }),
- zIndex: 65535,
- declutter: false,
- visible: false,
- renderMode: 'vector',
- map: map,
- style: null,
- }),
- ];
+ return ret;
})();
@@ -1544,9 +1515,7 @@ const infoMetadataAccordions = [];
}
};
const onClickFunction = function(layerList, event) {
- featureOverlayLayer.setVisible(false);
- featureOverlayLayer.changed();
- Popover.getInstance(popup)?.dispose();
+ disposePopover();
const searchParams = new URLSearchParams(location.hash.substring(1));
let layersParams = searchParams.get('layers') || '';
@@ -2231,4 +2200,5 @@ const infoMetadataAccordions = [];
};
})();
-popover(map, mapLayers, featureOverlayLayer);
+initPopupOverLay(map, document.getElementById('popup'));
+initPopover(map);
diff --git a/src/popover.js b/src/popover.js
index 81f65c0..bdcd5ae 100644
--- a/src/popover.js
+++ b/src/popover.js
@@ -1,16 +1,35 @@
+/***********************************************************************
+ * Copyright © 2024-2025 Guilhem Moulin <info@guilhem.se>
+ * Popup and feature overlays
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ **********************************************************************/
+
import Overlay from 'ol/Overlay.js';
import Stroke from 'ol/style/Stroke.js';
import Style from 'ol/style/Style.js';
+import VectorTileLayer from 'ol/layer/VectorTile.js';
import { Popover } from 'bootstrap';
-const popup = document.getElementById('popup');
-
/* TODO: this should really be refactored… */
-const layers = {
- 'mrr.appr_ec': {
- popoverTitle: 'Bearbetningskoncession \u2013 beviljad',
- popover: [
+const layers = {}
+
+layers.mrr = {
+ appr_ec: {
+ title: 'Bearbetningskoncession \u2013 beviljad',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Ägare', 'owners'],
@@ -25,9 +44,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appl_ec': {
- popoverTitle: 'Bearbetningskoncession \u2013 ansökt',
- popover: [
+ appl_ec: {
+ title: 'Bearbetningskoncession \u2013 ansökt',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Sökande', 'owners'],
@@ -38,9 +57,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appr_met': {
- popoverTitle: 'Undersökningstillstånd, metaller och industrimineral \u2013 beviljad',
- popover: [
+ appr_met: {
+ title: 'Undersökningstillstånd, metaller och industrimineral \u2013 beviljad',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Ägare', 'owners'],
@@ -55,9 +74,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appl_met': {
- popoverTitle: 'Undersökningstillstånd, metaller och industrimineral \u2013 ansökt',
- popover: [
+ appl_met: {
+ title: 'Undersökningstillstånd, metaller och industrimineral \u2013 ansökt',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Sökande', 'owners'],
@@ -68,9 +87,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appr_ogd': {
- popoverTitle: 'Undersökningstillstånd, olja, gas och diamant \u2013 beviljad',
- popover: [
+ appr_ogd: {
+ title: 'Undersökningstillstånd, olja, gas och diamant \u2013 beviljad',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Ägare', 'owners'],
@@ -85,9 +104,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appl_ogd': {
- popoverTitle: 'Undersökningstillstånd, olja, gas och diamant \u2013 ansökt',
- popover: [
+ appl_ogd: {
+ title: 'Undersökningstillstånd, olja, gas och diamant \u2013 ansökt',
+ fields: [
['Namn', 'name'],
['Koncessionsmineral', 'mineral'],
['Sökande', 'owners'],
@@ -98,9 +117,9 @@ const layers = {
//['Län', 'County'],
],
},
- 'mrr.appr_dl': {
- popoverTitle: 'Markanvisning till koncession',
- popover: [
+ appr_dl: {
+ title: 'Markanvisning till koncession',
+ fields: [
['Namn', 'name'],
['Tillhörande bearbetnings\u00ADkoncession(er)', 'conc_name'],
['Tillståndsid', 'licenceid', { classes: ['feature-attr-mrr-license-id'] }],
@@ -112,18 +131,20 @@ const layers = {
//['Län', 'County'],
],
},
+};
- 'svk.ledningar': {
- popoverTitle: 'Kraftledning (befintlig)',
- popover: [
+layers.svk = {
+ ledningar: {
+ title: 'Kraftledning (befintlig)',
+ fields: [
['Förläggning', 'Placement'],
['Spänning', 'Voltage', { unit: 'kV' }],
['Ledlängd', 'geom_length', { fn: 'length' }],
],
},
- 'svk.transmissionsnatsprojekt': {
- popoverTitle: 'Transmissionsnätsprojekt',
- popover: [
+ transmissionsnatsprojekt: {
+ title: 'Transmissionsnätsprojekt',
+ fields: [
['Projektnamn', 'Name'],
['Spänning', 'Voltage', { unit: 'kV' }],
['Länk', 'Url', { fn: function(v) {
@@ -140,10 +161,12 @@ const layers = {
}}],
],
},
+};
- 'vbk.area_current': {
- popoverTitle: 'Landbaserad projekteringsområde för vindkraft',
- popover: [
+layers.vbk = {
+ area_current: {
+ title: 'Landbaserad projekteringsområde för vindkraft',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Aktuella verk', 'AntalVerk'],
@@ -162,9 +185,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.area_notcurrent': {
- popoverTitle: 'Landbaserad projekteringsområde för vindkraft \u2013 ej aktuell',
- popover: [
+ area_notcurrent: {
+ title: 'Landbaserad projekteringsområde för vindkraft \u2013 ej aktuell',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Aktuella verk', 'AntalVerk'],
@@ -182,9 +205,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_completed': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 tillståndsansökan uppförd',
- popover: [
+ offshore_completed: {
+ title: 'Havsbaserad vindkraft \u2013 tillståndsansökan uppförd',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -208,9 +231,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_approved': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 tillståndsansökan beviljad',
- popover: [
+ offshore_approved: {
+ title: 'Havsbaserad vindkraft \u2013 tillståndsansökan beviljad',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -240,9 +263,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_amended': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 ändringsansökan',
- popover: [
+ offshore_amended: {
+ title: 'Havsbaserad vindkraft \u2013 ändringsansökan',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -267,9 +290,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_rejected': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 tillståndsansökan avslagen',
- popover: [
+ offshore_rejected: {
+ title: 'Havsbaserad vindkraft \u2013 tillståndsansökan avslagen',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -294,9 +317,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_appealed': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 överklagad',
- popover: [
+ offshore_appealed: {
+ title: 'Havsbaserad vindkraft \u2013 överklagad',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -324,9 +347,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_applied': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 tillståndsansökan inlämnad',
- popover: [
+ offshore_applied: {
+ title: 'Havsbaserad vindkraft \u2013 tillståndsansökan inlämnad',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -350,9 +373,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_consultation': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 samråd inför tillståndsansökan',
- popover: [
+ offshore_consultation: {
+ title: 'Havsbaserad vindkraft \u2013 samråd inför tillståndsansökan',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -375,9 +398,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_investigation': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 inledande undersökningar',
- popover: [
+ offshore_investigation: {
+ title: 'Havsbaserad vindkraft \u2013 inledande undersökningar',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -399,9 +422,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.offshore_revoked': {
- popoverTitle: 'Havsbaserad vindkraft \u2013 inte aktuell eller återkallad',
- popover: [
+ offshore_revoked: {
+ title: 'Havsbaserad vindkraft \u2013 inte aktuell eller återkallad',
+ fields: [
['Projektnamn', 'Projektnamn'],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Verksamhetsutövare', 'Organisationsnamn'],
@@ -430,9 +453,9 @@ const layers = {
['Senast uppdaterat', 'SenasteUppdaterat'],
],
},
- 'vbk.station_completed': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 uppfört',
- popover: [
+ station_completed: {
+ title: 'Landbaserad vindkraftverk \u2013 uppfört',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -456,9 +479,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_processed': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 handlagt',
- popover: [
+ station_processed: {
+ title: 'Landbaserad vindkraftverk \u2013 handlagt',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -480,9 +503,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_approved': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 beviljat',
- popover: [
+ station_approved: {
+ title: 'Landbaserad vindkraftverk \u2013 beviljat',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -505,9 +528,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_revoked': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 inte längre aktuell/återkallat',
- popover: [
+ station_revoked: {
+ title: 'Landbaserad vindkraftverk \u2013 inte längre aktuell/återkallat',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -530,9 +553,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_rejected': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 avslagit/nekat',
- popover: [
+ station_rejected: {
+ title: 'Landbaserad vindkraftverk \u2013 avslagit/nekat',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -555,9 +578,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_dismounted': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 nedmonterat',
- popover: [
+ station_dismounted: {
+ title: 'Landbaserad vindkraftverk \u2013 nedmonterat',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -580,9 +603,9 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
- 'vbk.station_appealed': {
- popoverTitle: 'Landbaserad vindkraftverk \u2013 överklagat',
- popover: [
+ station_appealed: {
+ title: 'Landbaserad vindkraftverk \u2013 överklagat',
+ fields: [
['Verk-ID', 'VerkID', { classes: ['feature-objid'] }],
['Områdes-ID', 'OmrID', { classes: ['feature-objid'] }],
['Projektnamn', 'Projektnamn'],
@@ -604,13 +627,15 @@ const layers = {
['Datum för senaste uppdatering av verk', 'SenasteUppdaterat'],
],
},
+};
+layers.avverk = {
/* Documentation at
* https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/utforda-avverkningar---produktbeskrivning.pdf
* */
- 'avverk.utford': {
- popoverTitle: 'Utförd avverkning',
- popover: [
+ utford: {
+ title: 'Utförd avverkning',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Registeringsår', 'ArendeAr'],
['Skogstyp', 'Skogstyp'],
@@ -629,9 +654,9 @@ const layers = {
/* Documentation at
* https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/yttre-granser-for-avverkningsanmalda-omraden---produktbeskrivning.pdf
* */
- 'avverk.anmald': {
- popoverTitle: 'Avverkningsanmälansområde',
- popover: [
+ anmald: {
+ title: 'Avverkningsanmälansområde',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Inkom datum', 'Inkomdatum'],
['Registeringsår', 'ArendeAr'],
@@ -648,10 +673,12 @@ const layers = {
['Avverkad areal', 'AvvHa', { unit: 'ha' }],
],
},
+};
- 'skydd.tilltradesforbud': {
- popoverTitle: 'Tillträdesförbud',
- popover: [
+layers.skyyd = {
+ tilltradesforbud: {
+ title: 'Tillträdesförbud',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Föreskriftsområde', 'FORSKRNAMN'],
['Namn', 'OBJEKTNAMN'],
@@ -664,9 +691,9 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.nationalpark': {
- popoverTitle: 'Nationalpark',
- popover: [
+ nationalpark: {
+ title: 'Nationalpark',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -685,9 +712,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.naturreservat': {
- popoverTitle: 'Naturreservat',
- popover: [
+ naturreservat: {
+ title: 'Naturreservat',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -706,9 +733,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.naturreservat_kommunalt': {
- popoverTitle: 'Kommunalt naturreservat',
- popover: [
+ naturreservat_kommunalt: {
+ title: 'Kommunalt naturreservat',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -727,9 +754,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.naturvardsomrade': {
- popoverTitle: 'Naturvårdsområde',
- popover: [
+ naturvardsomrade: {
+ title: 'Naturvårdsområde',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -748,9 +775,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.djur_och_vaxtskyddsomrade': {
- popoverTitle: 'Djur- och växtskyddsområde',
- popover: [
+ djur_och_vaxtskyddsomrade: {
+ title: 'Djur- och växtskyddsområde',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -769,9 +796,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.kulturreservat': {
- popoverTitle: 'Kulturreservat',
- popover: [
+ kulturreservat: {
+ title: 'Kulturreservat',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -790,9 +817,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.vattenskyddsomrade': {
- popoverTitle: 'Vattenskyddsområden',
- popover: [
+ vattenskyddsomrade: {
+ title: 'Vattenskyddsområden',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -811,9 +838,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.landskapsbildsskyddsomrade': {
- popoverTitle: 'Landskapsbildsskyddsområde',
- popover: [
+ landskapsbildsskyddsomrade: {
+ title: 'Landskapsbildsskyddsområde',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -832,9 +859,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.skogligt_biotopskyddsomrade': {
- popoverTitle: 'Biotopskydd i skogsmark',
- popover: [
+ skogligt_biotopskyddsomrade: {
+ title: 'Biotopskydd i skogsmark',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Biotopkategori', 'Biotyp'],
['Skogstyp', 'Naturtyp'],
@@ -856,9 +883,9 @@ const layers = {
}}],
],
},
- 'skydd.ovrigt_biotopskyddsomrade': {
- popoverTitle: 'Biotopskydd utanför skogsmark',
- popover: [
+ ovrigt_biotopskyddsomrade: {
+ title: 'Biotopskydd utanför skogsmark',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -877,9 +904,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.naturminne_yta': {
- popoverTitle: 'Naturminne (yta)',
- popover: [
+ naturminne_yta: {
+ title: 'Naturminne (yta)',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -898,9 +925,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.naturminne_punkt': {
- popoverTitle: 'Naturminne (punkt)',
- popover: [
+ naturminne_punkt: {
+ title: 'Naturminne (punkt)',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -916,9 +943,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.interimistiskt_forbud': {
- popoverTitle: 'Interimistiskt förbud',
- popover: [
+ interimistiskt_forbud: {
+ title: 'Interimistiskt förbud',
+ fields: [
['NVR-ID', 'NVRID', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
@@ -937,9 +964,9 @@ const layers = {
['Skogsmarksareal', 'SKOG_HA', { unit: 'ha' }],
],
},
- 'skydd.fageldirektivet': {
- popoverTitle: 'Fågeldirektivet (SPA)',
- popover: [
+ fageldirektivet: {
+ title: 'Fågeldirektivet (SPA)',
+ fields: [
['Områdeskod', 'SITE_CODE', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Områdestyp', 'OMRADESTYP'],
@@ -964,9 +991,9 @@ const layers = {
}}],
],
},
- 'skydd.habitatdirektivet': {
- popoverTitle: 'Art- och habitatdirektivet (SCI)',
- popover: [
+ habitatdirektivet: {
+ title: 'Art- och habitatdirektivet (SCI)',
+ fields: [
['Områdeskod', 'SITE_CODE', { classes: ['feature-objid'] }],
['Namn', 'NAMN'],
['Områdestyp', 'OMRADESTYP'],
@@ -991,16 +1018,16 @@ const layers = {
}}],
],
},
- 'skydd.helcom': {
- popoverTitle: 'Marina skyddade områden (Helcom MPA)',
- popover: [
+ helcom: {
+ title: 'Marina skyddade områden (Helcom MPA)',
+ fields: [
['Namn', 'NAME'],
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.ramsar': {
- popoverTitle: 'Ramsar-områden (Våtmarkskonventionen)',
- popover: [
+ ramsar: {
+ title: 'Ramsar-områden (Våtmarkskonventionen)',
+ fields: [
['Ramsar-ID', 'RAMSAR_ID', { classes: ['feature-objid'] }],
['Skyddstyp', 'SKYDDSTYP'],
['Namn', 'NAMN'],
@@ -1025,9 +1052,9 @@ const layers = {
}}],
],
},
- 'skydd.ospar': {
- popoverTitle: 'Marina skyddade områden (Ospar MPA)',
- popover: [
+ ospar: {
+ title: 'Marina skyddade områden (Ospar MPA)',
+ fields: [
['Ursprung', 'ORIGIN'],
['N2000-namn', 'NAMN_N2000'],
['MPA-ID', 'MPA_ID', { classes: ['feature-objid'] }],
@@ -1036,16 +1063,16 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.varldsarv': {
- popoverTitle: 'Världsarv med mycket höga naturvärden (Unesco)',
- popover: [
+ varldsarv: {
+ title: 'Världsarv med mycket höga naturvärden (Unesco)',
+ fields: [
['Namn', 'NAMN'],
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.biosfarsomraden': {
- popoverTitle: 'Biosfärsområde (Unesco)',
- popover: [
+ biosfarsomraden: {
+ title: 'Biosfärsområde (Unesco)',
+ fields: [
['Namn', 'NAMN'],
['Skyddstyp', 'SKYDDSTYP'],
['Länk', 'LINK', { fn: function(v) {
@@ -1063,9 +1090,9 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.naturvardsavtal': {
- popoverTitle: 'Naturvårdsavtal (Naturvårdsverket, Länsstyrelsen)',
- popover: [
+ naturvardsavtal: {
+ title: 'Naturvårdsavtal (Naturvårdsverket, Länsstyrelsen)',
+ fields: [
['ID', 'ID', { classes: ['feature-objid'] }],
['Namn', 'OBJNAMN'],
['Fastighet', 'FASTBET', { classes: ['feature-objid'] }],
@@ -1076,9 +1103,9 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'skydd.naturvardsavtal_skogsstyrelsen': {
- popoverTitle: 'Naturvårdsavtal (Skogsstyrelsen)',
- popover: [
+ naturvardsavtal_skogsstyrelsen: {
+ title: 'Naturvårdsavtal (Skogsstyrelsen)',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Registeringsår', 'ArendeAr'],
['Biotopkategori', 'NvaTyp'],
@@ -1101,9 +1128,9 @@ const layers = {
['Undertyp', 'Undertyp'],
],
},
- 'skydd.atervatningsavtal': {
- popoverTitle: 'Återvätningsavtal',
- popover: [
+ atervatningsavtal: {
+ title: 'Återvätningsavtal',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Ärendeår', 'ArendeAr'],
['Avtalat datum', 'AvtalatDatum'],
@@ -1122,9 +1149,12 @@ const layers = {
}}],
],
},
- 'nv.naturvarde_sks': {
- popoverTitle: 'Objekt med naturvärden (Skogsstyrelsen)',
- popover: [
+};
+
+layers.nv = {
+ naturvarde_sks: {
+ title: 'Objekt med naturvärden (Skogsstyrelsen)',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Namn', 'Objnamn'],
['Datum för fältinventering', 'Datinv'],
@@ -1149,9 +1179,9 @@ const layers = {
}}],
],
},
- 'nv.nyckelbiotop': {
- popoverTitle: 'Nyckelbiotop (Skogsstyrelsen)',
- popover: [
+ nyckelbiotop: {
+ title: 'Nyckelbiotop (Skogsstyrelsen)',
+ fields: [
['Ärendebeteckning', 'Beteckn', { classes: ['feature-objid'] }],
['Namn', 'Objnamn'],
['Datum för fältinventering', 'Datinv'],
@@ -1181,9 +1211,9 @@ const layers = {
}}],
],
},
- 'nv.nyckelbiotop_storskogsbruk': {
- popoverTitle: 'Nyckelbiotop (storskogsbruket)',
- popover: [
+ nyckelbiotop_storskogsbruk: {
+ title: 'Nyckelbiotop (storskogsbruket)',
+ fields: [
['Uppgifter lämnade av', 'Org'],
['Inkom datum', 'InkomDatum'],
['Areal', 'geom_area', { fn: 'area' }],
@@ -1201,9 +1231,9 @@ const layers = {
}}],
],
},
- 'nv.sumpskog': {
- popoverTitle: 'Sumpskog',
- popover: [
+ sumpskog: {
+ title: 'Sumpskog',
+ fields: [
['Objektnamn', 'Namn'],
['Skogstyp', 'Tradtext'],
['Hydrologisk typ', 'Hydrtext'],
@@ -1237,17 +1267,17 @@ const layers = {
}}],
],
},
- 'nv.pagaende_naturreservatsbildning': {
- popoverTitle: 'Pågående naturreservatsbildning',
- popover: [
+ pagaende_naturreservatsbildning: {
+ title: 'Pågående naturreservatsbildning',
+ fields: [
['Objektnamn', 'NAMN'],
['Senast justerat', 'GRANSJUST'], /* XXX unclear what "GRANSJUST" means, just a guess */
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'nv.snus': {
- popoverTitle: 'Skyddsvärd statlig skog',
- popover: [
+ snus: {
+ title: 'Skyddsvärd statlig skog',
+ fields: [
['Objektnamn', 'NAMN'],
['År', 'AR'],
['Naturgeografisk region', 'NATURGEOGR', { classes: ['feature-objid'] }],
@@ -1269,10 +1299,12 @@ const layers = {
['Källor', 'KALLOR'],
],
},
+};
- 'ri.naturvard': {
- popoverTitle: 'Riksintresse naturvård',
- popover: [
+layers.ri = {
+ naturvard: {
+ title: 'Riksintresse naturvård',
+ fields: [
['Namn', 'NAMN'],
['Skydd', 'SKYDD'],
['Ämnesområde', 'AMNESOMRAD'],
@@ -1295,9 +1327,9 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'ri.friluftsliv': {
- popoverTitle: 'Riksintresse friluftsliv',
- popover: [
+ friluftsliv: {
+ title: 'Riksintresse friluftsliv',
+ fields: [
['Namn', 'NAMN'],
['Skydd', 'SKYDD'],
['Ämnesområde', 'AMNESOMR'],
@@ -1336,9 +1368,9 @@ const layers = {
['Areal vatten', 'AREA_VATTE', { unit: 'ha' }],
],
},
- 'ri.rorligt_friluftsliv': {
- popoverTitle: 'Riksintresse rörligt friluftsliv (MB 4 kap 1§ och 2§)',
- popover: [
+ rorligt_friluftsliv: {
+ title: 'Riksintresse rörligt friluftsliv (MB 4 kap 1§ och 2§)',
+ fields: [
['Namn', 'NAMN'],
//['Original-ID', 'ORIGINALID', { classes: ['feature-objid'] }],
['Beskrivning', 'BESKRIVNIN'],
@@ -1362,9 +1394,9 @@ const layers = {
['Referens', 'REFERENS'],
],
},
- 'ri.obruten_kust': {
- popoverTitle: 'Riksintresse obruten kust (MB 4 kap 3§)',
- popover: [
+ obruten_kust: {
+ title: 'Riksintresse obruten kust (MB 4 kap 3§)',
+ fields: [
['Namn', 'NAMN'],
//['Original-ID', 'ORIGINALID', { classes: ['feature-objid'] }],
['Beskrivning', 'BESKRIVNIN'],
@@ -1389,9 +1421,9 @@ const layers = {
['Referens', 'REFERENS'],
],
},
- 'ri.obrutet_fjall': {
- popoverTitle: 'Riksintresse obrutet fjäll (MB 4 kap 5§)',
- popover: [
+ obrutet_fjall: {
+ title: 'Riksintresse obrutet fjäll (MB 4 kap 5§)',
+ fields: [
['Namn', 'NAMN'],
//['Original-ID', 'ORIGINALID', { classes: ['feature-objid'] }],
['Beskrivning', 'BESKRIVNIN'],
@@ -1414,9 +1446,9 @@ const layers = {
['Referens', 'REFERENS'],
],
},
- 'ri.skyddade_vattendrag': {
- popoverTitle: 'Riksintresse skyddade vattendrag (MB 4 kap 6§)',
- popover: [
+ skyddade_vattendrag: {
+ title: 'Riksintresse skyddade vattendrag (MB 4 kap 6§)',
+ fields: [
['Namn', 'NAMN'],
//['Original-ID', 'ORIGINALID', { classes: ['feature-objid'] }],
['Beskrivning', 'BESKRIVNIN'],
@@ -1441,19 +1473,21 @@ const layers = {
['Referens', 'REFERENS'],
],
},
+};
- 'ren.betesomrade': {
- popoverTitle: 'Samebyarnas betesområde',
- popover: [
+layers.ren = {
+ betesomrade: {
+ title: 'Samebyarnas betesområde',
+ fields: [
['Sameby', 'NAMN'],
['Samebys typ', 'SAMEBY_TYP'],
['Signatur', 'SIGNATUR'],
['Aktualitet', 'AKTUALITET'],
],
},
- 'ren.flyttled': {
- popoverTitle: 'Samebyarnas markanvändningsredovisning \u2013 flyttled',
- popover: [
+ flyttled: {
+ title: 'Samebyarnas markanvändningsredovisning \u2013 flyttled',
+ fields: [
['Led-ID', 'LED_ID', { classes: ['feature-objid'], fn: (v) => v === 0 ? '' : v }],
['Sameby #1', 'SAMEBY1'],
['Sameby #2', 'SAMEBY2'],
@@ -1467,18 +1501,18 @@ const layers = {
['Ledlängd', 'geom_length', { fn: 'length' }],
],
},
- 'ren.riks_ren': {
- popoverTitle: 'Riksintresse rennäring',
- popover: [
+ riks_ren: {
+ title: 'Riksintresse rennäring',
+ fields: [
['Lagrum', 'LAGRUM'],
['Aktualitet', 'AKTUALITET'],
['Signatur', 'SIGNATUR'],
['Areal', 'geom_area', { fn: 'area' }],
],
},
- 'ren.omr_riks': {
- popoverTitle: '(Kärn)områden av riksintresse rennäring',
- popover: [
+ omr_riks: {
+ title: '(Kärn)områden av riksintresse rennäring',
+ fields: [
['Områdes-ID', 'OMR_NR', { classes: ['feature-objid'] }],
['Länk', 'LANK'],
['Årets runt', 'ARET_RUNT'],
@@ -1489,13 +1523,15 @@ const layers = {
['Areal', 'geom_area', { fn: 'area' }],
],
},
+};
+layers.misc = {
/* Documentation at
* https://www.smhi.se/polopoly_fs/1.34541!/dammprod%202013_3%2C%20beskrivning%2C%20SVAR2012_2.pdf
* */
- 'misc.dammar': {
- popoverTitle: 'Damm',
- popover: [
+ dammar: {
+ title: 'Damm',
+ fields: [
['Dammenhetens namn', 'DNamn'],
['Dammanläggningens namn', 'Namn'],
['Länsnr', 'LST_OBJID', { classes: ['feature-objid'] }],
@@ -1536,9 +1572,9 @@ const layers = {
],
},
- 'misc.gigafactories': {
- popoverTitle: 'Stor industrisatsning',
- popover: [
+ gigafactories: {
+ title: 'Stor industrisatsning',
+ fields: [
['Namn', 'Name'],
['Länk', 'Url', { fn: function(v) {
if (v == null | v === '') {
@@ -1556,15 +1592,136 @@ const layers = {
},
};
-/* popup and feature overlays */
-export const popover = function(map, mapLayers, featureOverlayLayer) {
- const popupOverlay = new Overlay({
+
+
+/* format value to HTML */
+const formatValue = function(value, options) {
+ let unit = options?.unit;
+ if (options?.fn == null) {
+ /* no-op */
+ } else if (typeof options.fn === 'function') {
+ value = options.fn(value);
+ } else if (options.fn === 'length' && typeof value === 'number' && unit == null) {
+ if (value < 1000) {
+ unit = 'm';
+ } else {
+ value /= 1000;
+ value = Math.round(value*100) / 100;
+ unit = 'km';
+ }
+ } else if (options.fn === 'area' && typeof value === 'number' && unit == null) {
+ if (value < 10000) {
+ unit = 'm²';
+ } else if (value < 10000 * 10000) {
+ value /= 10000;
+ unit = 'ha';
+ } else {
+ value /= 1000000;
+ unit = 'km²';
+ }
+ value = Math.round(value*100) / 100;
+ }
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof HTMLElement) {
+ return value;
+ }
+ switch (typeof value) {
+ case 'boolean':
+ return document.createTextNode(value ? 'Ja' : 'Nej');
+ case 'string':
+ return document.createTextNode(value);
+ case 'number':
+ if (unit != null) {
+ return document.createTextNode(value.toLocaleString('sv-SE') + '\u202F' + unit);
+ }
+ return document.createTextNode(value.toString());
+ default:
+ return null;
+ }
+};
+
+/* turn the properties into a fine table */
+const formatFeaturePropertiesToHTML = function(properties) {
+ const table = document.createElement('table');
+ table.classList.add('table', 'table-sm', 'table-borderless', 'table-hover');
+
+ const tbody = document.createElement('tbody');
+ table.appendChild(tbody);
+
+ const def = layers[properties.layer_group][properties.layer];
+ def.fields.forEach(function([desc, key, opts]) {
+ const tr = document.createElement('tr');
+ tbody.appendChild(tr);
+
+ const td1 = document.createElement('td');
+ tr.appendChild(td1);
+ const textDesc = document.createTextNode(desc);
+ td1.appendChild(textDesc);
+
+ const td2 = document.createElement('td');
+ tr.appendChild(td2);
+ const v = formatValue(properties[key], opts);
+ if (v != null) {
+ td2.appendChild(v);
+ }
+ opts?.classes?.forEach?.((c) => td2.classList.add(c));
+ });
+
+ const content = document.createElement('div');
+ if (def.title != null) {
+ const h = document.createElement('h6');
+ content.appendChild(h);
+ const textNode = document.createTextNode(def.title);
+ h.appendChild(textNode);
+ }
+
+ content.appendChild(table);
+ return content;
+};
+
+let popupOverlay = null;
+export const initPopupOverLay = function(map, element) {
+ popupOverlay = new Overlay({
stopEvent: true,
- element: popup,
+ element: element,
});
map.addOverlay(popupOverlay);
+};
- let popover, overlayAttributes = [], overlayAttrIdx = 0;
+let featureOverlayLayer = null;
+let overlayAttributes = [],
+ overlayAttrIdx = 0,
+ mapSources = {};
+const disposeFeatureOverlay = function() {
+ if (featureOverlayLayer?.getVisible?.()) {
+ featureOverlayLayer.setVisible(false);
+ featureOverlayLayer.changed();
+ }
+ /* clear the overlay list */
+ overlayAttributes = [];
+ overlayAttrIdx = 0;
+ mapSources = {};
+}
+
+let popover = null;
+export const disposePopover = function() {
+ disposeFeatureOverlay();
+ if (popover?.tip != null) {
+ popover.dispose();
+ }
+};
+
+export const initPopover = function(map) {
+ featureOverlayLayer = new VectorTileLayer({
+ zIndex: 65535,
+ declutter: false,
+ visible: false,
+ renderMode: 'vector',
+ style: null,
+ map: map,
+ });
const header = document.createElement('div');
header.classList.add('d-flex');
@@ -1573,11 +1730,14 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
headerGrabbingArea.classList.add('flex-grow-1', 'grabbing-area', 'pe-2', 'me-2');
header.appendChild(headerGrabbingArea);
+ const pageNode = document.createElement('h6');
+ headerGrabbingArea.appendChild(pageNode);
+
headerGrabbingArea.onmousedown = function(event) {
if (event.button != 0) {
return;
}
- const popoverTip = Popover.getInstance(popup).tip;
+ const popoverTip = popover.tip;
if (popoverTip.classList.contains('popover-maximized')) {
return;
}
@@ -1615,9 +1775,6 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
};
};
- const pageNode = document.createElement('h6');
- headerGrabbingArea.appendChild(pageNode);
-
const pageNum = document.createElement('span');
const pageCount = document.createElement('span');
pageNode.appendChild(document.createTextNode('Träff '));
@@ -1632,21 +1789,18 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
}),
});
const updateFeatureOverlayLayer = function(layer_group, layer, id) {
- const lyr = mapLayers[layer_group];
- if (lyr == null) {
+ const source = mapSources[layer_group];
+ if (source == null) {
return;
}
- const urls = lyr.getSource().getUrls();
- const source = featureOverlayLayer.getSource();
- if (source.getUrls().length < 1 || source.getUrls()[0] !== urls[0]) {
+ if (featureOverlayLayer.getSource() !== source) {
+ /* console.log('Updating source for feature overlay layer'); */
featureOverlayLayer.setVisible(false);
- source.setUrls(urls);
+ featureOverlayLayer.setSource(source);
}
featureOverlayLayer.setStyle(function(feature) {
if (feature.getId() === id && feature.getProperties().layer === layer) {
return featureOverlayStyle;
- } else {
- return undefined;
}
});
featureOverlayLayer.setVisible(true);
@@ -1732,115 +1886,24 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
btnClose.setAttribute('type', 'button');
btnClose.title = 'Stäng';
btnClose.setAttribute('aria-label', btnClose.title);
- btnClose.onclick = function() {
- featureOverlayLayer.setVisible(false);
- featureOverlayLayer.changed();
- popover?.dispose();
- };
+ btnClose.onclick = disposePopover;
header.appendChild(btnPrev);
header.appendChild(btnNext);
header.appendChild(btnExpand);
header.appendChild(btnClose);
- const formatFeaturePropertiesToHTML = function(properties) {
- /* turn the properties into a fine table */
- const table = document.createElement('table');
- table.classList.add('table', 'table-sm', 'table-borderless', 'table-hover');
-
- const tbody = document.createElement('tbody');
- table.appendChild(tbody);
-
- const def = layers[properties.layer_group + '.' + properties.layer];
- def.popover.forEach(function([desc, key, opts]) {
- let v = properties[key];
- if (opts === undefined) {
- opts = {};
- }
- if (opts.fn !== undefined) {
- if (opts.fn === 'length') {
- if (v < 1000) {
- opts.unit = 'm';
- } else {
- v /= 1000;
- v = Math.round(v*100) / 100;
- opts.unit = 'km';
- }
- } else if (opts.fn === 'area') {
- if (v < 10000) {
- opts.unit = 'm²';
- } else if (v < 10000 * 10000) {
- v /= 10000;
- opts.unit = 'ha';
- } else {
- v /= 1000000;
- opts.unit = 'km²';
- }
- v = Math.round(v*100) / 100;
- } else {
- v = opts.fn(v);
- }
- }
- if (v == null) {
- v = document.createTextNode('');
- } else if (!(v instanceof HTMLElement)) {
- if (typeof(v) === 'number' && opts.unit !== undefined) {
- v = v.toLocaleString('sv-SE');
- } else if (typeof(v) === 'boolean') {
- v = v ? 'Ja' : 'Nej';
- }
- if (opts.unit !== undefined && v !== '') {
- v += '\u202F' + opts.unit;
- }
- v = document.createTextNode(v);
- }
-
- const tr = document.createElement('tr');
- tbody.appendChild(tr);
-
- const td1 = document.createElement('td');
- tr.appendChild(td1);
- const textDesc = document.createTextNode(desc);
- td1.appendChild(textDesc);
-
- const td2 = document.createElement('td');
- tr.appendChild(td2);
- td2.appendChild(v);
- if (opts.classes !== undefined) {
- opts.classes.forEach((c) => td2.classList.add(c));
- }
- });
-
- const content = document.createElement('div');
- if (def.popoverTitle !== undefined) {
- const h = document.createElement('h6');
- content.appendChild(h);
- const textNode = document.createTextNode(def.popoverTitle);
- h.appendChild(textNode);
- }
-
- content.appendChild(table);
- return content;
- };
-
const container0 = map.getViewport().getElementsByClassName('ol-overlaycontainer-stopevent')[0];
map.on('singleclick', function(event) {
- /* clear the overlay list */
- featureOverlayLayer.setVisible(false);
- featureOverlayLayer.changed();
- overlayAttributes = [];
- overlayAttrIdx = 0;
+ disposeFeatureOverlay();
/* dispose any pre-existing popover if not in detached mode */
- popover = Popover.getInstance(popup);
- if (popover !== null) {
- const popoverTip = popover.tip;
- if (popoverTip !== null && !popoverTip.classList.contains('popover-detached')) {
- popover.dispose();
- }
+ popover = Popover.getInstance(popupOverlay.element);
+ if (popover?.tip != null && !popover.tip.classList.contains('popover-detached')) {
+ popover.dispose();
}
- const size = map.getSize();
+ const size = event.map.getSize();
if (size[0] < 576 || size[1] < 576) {
return;
}
@@ -1858,37 +1921,41 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
btnExpand.title = btnExpandTitle;
btnExpand.setAttribute('aria-label', btnExpand.title);
- const fetch_body = []
- map.forEachFeatureAtPixel(event.pixel, function(feature, layer) {
+ const fetch_body = [];
+ event.map.forEachFeatureAtPixel(event.pixel, function(feature, layer) {
const layerGroup = layer.get('layerGroup');
const layerName = feature.getProperties().layer;
- const def = layers[layerGroup + '.' + layerName];
- if (def?.popover != null) {
+ mapSources[layerGroup] ??= layer.getSource();
+ const def = layerName != null ? layers[layerGroup][layerName] : null;
+ if (def?.fields == null) {
/* skip layers which didn't opt-in for popover */
- if (!fetch_body.length) {
- document.body.classList.add('inprogress');
- if (popover?.tip != null) {
- popover.tip.classList.add('inprogress');
- }
- }
- fetch_body.push({
- layer_group: layerGroup,
- layer: layerName,
- fid: feature.getId() ?? -1,
- });
- if (fetch_body.length >= 100) {
- return true; /* enough matches already, stop detection here */
- }
+ return false;
+ }
+ if (fetch_body.length === 0) {
+ /* first feature in the list */
+ document.body.classList.add('inprogress');
+ popover?.tip?.classList?.add?.('inprogress');
+ }
+ fetch_body.push({
+ layer_group: layerGroup,
+ layer: layerName,
+ fid: feature.getId() ?? -1,
+ });
+ if (fetch_body.length >= 100) {
+ return true; /* enough matches already, stop detection here */
}
}, {
hitTolerance: 5,
checkWrapped: false,
- layerFilter: (l) => l.get('layerGroup') != null,
+ layerFilter: (lyr) => lyr.get('layerGroup') != null,
});
if (fetch_body.length === 0) {
- /* dispose pre-detached popover */
- popover?.dispose();
+ /* no feature at pixel (or only within layers which didn't opt-in for popover) */
+ if (popover?.tip != null) {
+ /* dispose pre-detached popover */
+ popover.dispose();
+ }
return;
}
@@ -1896,8 +1963,8 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
method: 'POST',
body: JSON.stringify(fetch_body),
headers: {
- 'Content-Type': 'application/json; charset=UTF-8'
- }
+ 'Content-Type': 'application/json; charset=UTF-8',
+ },
})
.then(function(resp) {
if (resp.status === 200) {
@@ -1910,10 +1977,13 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
/* the data is received from the CGI in the order it was sent */
/* TODO optimizations on the CGI would break the above assumption, so the
* decoded JSON response would need to be reordered to match fetch_body */
- overlayAttributes = data
+ overlayAttributes = data;
if (overlayAttributes.length === 0) {
- /* dispose pre-detached popover */
- popover?.dispose();
+ /* couldn't fetch any attribute for feature(s) at pixel */
+ if (popover?.tip != null) {
+ /* dispose pre-detached popover */
+ popover.dispose();
+ }
return;
}
@@ -1931,7 +2001,7 @@ export const popover = function(map, mapLayers, featureOverlayLayer) {
const attr = overlayAttributes[0];
updateFeatureOverlayLayer(attr.layer_group, attr.layer, attr.ogc_fid);
- popover = new Popover(popup, {
+ popover = new Popover(popupOverlay.element, {
template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div>' +
'<div class="popover-header"></div><div class="popover-body"></div></div>',
title: header,