fix(geoportal): fix basemap switching + OpenTopoMap maxzoom 17
- 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) <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@ const LAYER_IDS = {
|
||||
} as const;
|
||||
|
||||
/** Basemap tile definitions */
|
||||
const BASEMAP_TILES: Record<BasemapId, { tiles: string[]; attribution: string; tileSize: number }> = {
|
||||
const BASEMAP_TILES: Record<BasemapId, { tiles: string[]; attribution: string; tileSize: number; maxzoom?: number }> = {
|
||||
osm: {
|
||||
tiles: [
|
||||
"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
@@ -79,6 +79,7 @@ const BASEMAP_TILES: Record<BasemapId, { tiles: string[]; attribution: string; t
|
||||
attribution:
|
||||
'© <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
|
||||
tileSize: 256,
|
||||
maxzoom: 17,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -231,47 +232,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
||||
}
|
||||
}, [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<MapViewerHandle, MapViewerProps>(
|
||||
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<MapViewerHandle, MapViewerProps>(
|
||||
setMapReady(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [resolvedMartinUrl]);
|
||||
}, [resolvedMartinUrl, basemap]);
|
||||
|
||||
/* ---- Sync center/zoom prop changes ---- */
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user