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;
|
} as const;
|
||||||
|
|
||||||
/** Basemap tile definitions */
|
/** 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: {
|
osm: {
|
||||||
tiles: [
|
tiles: [
|
||||||
"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
@@ -79,6 +79,7 @@ const BASEMAP_TILES: Record<BasemapId, { tiles: string[]; attribution: string; t
|
|||||||
attribution:
|
attribution:
|
||||||
'© <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
|
'© <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
|
||||||
tileSize: 256,
|
tileSize: 256,
|
||||||
|
maxzoom: 17,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,47 +232,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
|||||||
}
|
}
|
||||||
}, [mapReady, layerVisibility, applyLayerVisibility]);
|
}, [mapReady, layerVisibility, applyLayerVisibility]);
|
||||||
|
|
||||||
/* ---- Basemap switching ---- */
|
/* ---- Map initialization (recreates on basemap change) ---- */
|
||||||
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 ---- */
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!containerRef.current) return;
|
if (!containerRef.current) return;
|
||||||
|
|
||||||
@@ -295,13 +256,13 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
|||||||
type: "raster",
|
type: "raster",
|
||||||
source: "basemap",
|
source: "basemap",
|
||||||
minzoom: 0,
|
minzoom: 0,
|
||||||
maxzoom: 19,
|
maxzoom: initialBasemap.maxzoom ?? 19,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
center: center ?? DEFAULT_CENTER,
|
center: center ?? DEFAULT_CENTER,
|
||||||
zoom: zoom ?? DEFAULT_ZOOM,
|
zoom: zoom ?? DEFAULT_ZOOM,
|
||||||
maxZoom: 20,
|
maxZoom: initialBasemap.maxzoom ?? 20,
|
||||||
});
|
});
|
||||||
|
|
||||||
mapRef.current = map;
|
mapRef.current = map;
|
||||||
@@ -555,7 +516,7 @@ export const MapViewer = forwardRef<MapViewerHandle, MapViewerProps>(
|
|||||||
setMapReady(false);
|
setMapReady(false);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [resolvedMartinUrl]);
|
}, [resolvedMartinUrl, basemap]);
|
||||||
|
|
||||||
/* ---- Sync center/zoom prop changes ---- */
|
/* ---- Sync center/zoom prop changes ---- */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user