From 2248ecc5d3244a6fe9b6b4083542ba803dee6427 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Mon, 23 Mar 2026 18:24:47 +0200 Subject: [PATCH] fix(geoportal): fix basemap switching + OpenTopoMap maxzoom 17 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Basemap switching now recreates the map (basemap in useEffect deps) instead of buggy remove/re-add that swallowed errors - OpenTopoMap maxzoom set to 17 (was requesting z19 → 400 errors) - Basemap maxzoom applied to both source and map maxZoom Note: Martin vector tiles return 404 — PostGIS views or Martin container need to be checked on the server. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../geoportal/components/map-viewer.tsx | 51 +++---------------- 1 file changed, 6 insertions(+), 45 deletions(-) diff --git a/src/modules/geoportal/components/map-viewer.tsx b/src/modules/geoportal/components/map-viewer.tsx index ea741c5..77a008c 100644 --- a/src/modules/geoportal/components/map-viewer.tsx +++ b/src/modules/geoportal/components/map-viewer.tsx @@ -53,7 +53,7 @@ const LAYER_IDS = { } as const; /** Basemap tile definitions */ -const BASEMAP_TILES: Record = { +const BASEMAP_TILES: Record = { osm: { tiles: [ "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png", @@ -79,6 +79,7 @@ const BASEMAP_TILES: RecordOpenTopoMap (CC-BY-SA)', tileSize: 256, + maxzoom: 17, }, }; @@ -231,47 +232,7 @@ export const MapViewer = forwardRef( } }, [mapReady, layerVisibility, applyLayerVisibility]); - /* ---- Basemap switching ---- */ - useEffect(() => { - const map = mapRef.current; - if (!map || !mapReady) return; - - const source = map.getSource("basemap") as maplibregl.RasterTileSource | undefined; - if (!source) return; - - const def = BASEMAP_TILES[basemap]; - // Update tiles by re-adding the source - // MapLibre doesn't support changing tiles on existing source, so we rebuild - try { - // Remove all layers that depend on basemap source, then remove source - if (map.getLayer("basemap-tiles")) map.removeLayer("basemap-tiles"); - map.removeSource("basemap"); - - map.addSource("basemap", { - type: "raster", - tiles: def.tiles, - tileSize: def.tileSize, - attribution: def.attribution, - }); - - // Re-add basemap layer at bottom - const firstLayerId = map.getStyle().layers[0]?.id; - map.addLayer( - { - id: "basemap-tiles", - type: "raster", - source: "basemap", - minzoom: 0, - maxzoom: 19, - }, - firstLayerId // insert before first existing layer - ); - } catch { - // Fallback: if anything fails, the map still works - } - }, [basemap, mapReady]); - - /* ---- Map initialization ---- */ + /* ---- Map initialization (recreates on basemap change) ---- */ useEffect(() => { if (!containerRef.current) return; @@ -295,13 +256,13 @@ export const MapViewer = forwardRef( type: "raster", source: "basemap", minzoom: 0, - maxzoom: 19, + maxzoom: initialBasemap.maxzoom ?? 19, }, ], }, center: center ?? DEFAULT_CENTER, zoom: zoom ?? DEFAULT_ZOOM, - maxZoom: 20, + maxZoom: initialBasemap.maxzoom ?? 20, }); mapRef.current = map; @@ -555,7 +516,7 @@ export const MapViewer = forwardRef( setMapReady(false); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [resolvedMartinUrl]); + }, [resolvedMartinUrl, basemap]); /* ---- Sync center/zoom prop changes ---- */ useEffect(() => {