From 69f5e65495addcd33e5231c7ffdd2354c7c30f65 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Mon, 5 Oct 2026 14:04:02 +0200 Subject: [PATCH] feat(assets): add basemap and orthophoto switcher to nature location detail map - Include LayerSwitcherControl on the nature location detail map. - Support standard vector, aerial orthophotos, and regional basemaps from window.MAP_BACKGROUNDS. - Ensure proper z-index layer ordering so nature polygons, trees, and equipments remain above raster basemaps. - Update unit tests to verify layer switcher integration. --- .../static/assets/nature_location_detail.js | 84 +++++++++++++++++++ .../assets/nature_locations_detail.html | 1 + loko/assets/tests.py | 2 + 3 files changed, 87 insertions(+) diff --git a/loko/assets/static/assets/nature_location_detail.js b/loko/assets/static/assets/nature_location_detail.js index 66c3215..52b8a0d 100644 --- a/loko/assets/static/assets/nature_location_detail.js +++ b/loko/assets/static/assets/nature_location_detail.js @@ -18,6 +18,89 @@ document.addEventListener('DOMContentLoaded', function () { antialias: true }); + // ── Helper to place raster basemaps below nature layers ── + function getBasemapBeforeLayer(m) { + if (!m || !m.getStyle) return undefined; + if (m.getLayer('nature-location-fill')) return 'nature-location-fill'; + if (m.getLayer('nature-location-outline')) return 'nature-location-outline'; + if (m.getLayer('layer-surfaces-fill')) return 'layer-surfaces-fill'; + if (m.getLayer('layer-surfaces-outline')) return 'layer-surfaces-outline'; + if (m.getLayer('layer-shrubs')) return 'layer-shrubs'; + if (m.getLayer('layer-benches')) return 'layer-benches'; + if (m.getLayer('layer-trees')) return 'layer-trees'; + return undefined; + } + + // ── Ensure strict layer stacking order on top of basemaps ── + function reorderNatureLayers() { + const layerOrder = [ + 'nature-location-fill', + 'nature-location-outline', + 'layer-surfaces-fill', + 'layer-surfaces-outline', + 'layer-shrubs', + 'layer-benches', + 'layer-trees', + ]; + layerOrder.forEach(function (layerId) { + if (map.getLayer(layerId)) { + try { + map.moveLayer(layerId); + } catch (e) { + // ignore + } + } + }); + } + + // Add layer switcher control for basemaps / orthophotos + if (typeof LayerSwitcherControl !== 'undefined') { + const layerSwitcher = new LayerSwitcherControl({ + layers: [{ + id: 'basemap', + name: 'Fonds de plan & Orthophotos', + icon: 'satellite', + group: 'basemap', + beforeLayer: getBasemapBeforeLayer, + onLayerAdded: () => reorderNatureLayers(), + onVisibilityChange: () => reorderNatureLayers(), + layer: { + type: 'raster', + paint: { 'raster-opacity': 1 } + }, + basemaps: (window.MAP_BACKGROUNDS && window.MAP_BACKGROUNDS.length > 0) ? window.MAP_BACKGROUNDS : undefined, + sublayers: [ + { + id: 'urbis', + name: window.MAP_ORTHO_WMS_NAME || 'Urbis (Bruxelles)', + default: true, + source: { + type: 'raster', + tiles: [ + window.MAP_ORTHO_WMS_URL || 'https://geoservices-urbis.irisnet.be/geoserver/urbisgrid/wms?service=WMS&version=1.3.0&request=GetMap&layers=Ortho&styles=&format=image/png&transparent=true&width=256&height=256&crs=EPSG:3857&bbox={bbox-epsg-3857}' + ], + tileSize: 256, + attribution: window.MAP_ORTHO_WMS_ATTRIBUTION || '© Brussels UrbIS' + } + }, + { + id: 'vlaanderen', + name: 'Vlaanderen 2023', + source: { + type: 'raster', + tiles: [ + 'https://geo.api.vlaanderen.be/OMW/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=omwrgb23vl&STYLE=&FORMAT=image/png&TILEMATRIXSET=GoogleMapsVL&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}' + ], + tileSize: 256, + attribution: '© Digitaal Vlaanderen - Orthofoto 2023' + } + } + ] + }] + }); + map.addControl(layerSwitcher, 'top-right'); + } + // Add navigation and fullscreen controls map.addControl(new maplibregl.NavigationControl({ visualizePitch: true }), 'top-right'); map.addControl(new maplibregl.FullscreenControl(), 'top-right'); @@ -190,6 +273,7 @@ document.addEventListener('DOMContentLoaded', function () { duration: 800 }); } + reorderNatureLayers(); // 3. Interactive Popups const interactiveLayers = [ diff --git a/loko/assets/templates/assets/nature_locations_detail.html b/loko/assets/templates/assets/nature_locations_detail.html index ea824a8..8a6d83c 100644 --- a/loko/assets/templates/assets/nature_locations_detail.html +++ b/loko/assets/templates/assets/nature_locations_detail.html @@ -701,5 +701,6 @@ const assets_geojson = JSON.parse(document.getElementById("assets_geojson_value").textContent); + {% endblock script %} diff --git a/loko/assets/tests.py b/loko/assets/tests.py index fb11182..23470bd 100644 --- a/loko/assets/tests.py +++ b/loko/assets/tests.py @@ -5565,6 +5565,7 @@ class NatureLocationDetailViewTest(TestCase): self.assertContains(response, "SHR-001") self.assertContains(response, "BNC-001") self.assertContains(response, "Quercus robur") + self.assertContains(response, "layer-switcher-control.js") self.assertContains(response, "nature_location_detail.js") def test_nature_locations_detail_view_empty(self): @@ -5592,4 +5593,5 @@ class NatureLocationDetailViewTest(TestCase): self.assertEqual(len(response.context['documents']), 0) self.assertContains(response, "Aucune surface végétalisée enregistrée") self.assertContains(response, "Aucun arbre enregistré") + self.assertContains(response, "layer-switcher-control.js")