From 6f7a82af4c03935e52dcdfd62114c7dd79ddc413 Mon Sep 17 00:00:00 2001 From: htlee Date: Sun, 15 Feb 2026 14:29:19 +0900 Subject: [PATCH] fix(map): stop hiding raster base and reset decks on projection switch --- apps/web/src/widgets/map3d/Map3D.tsx | 36 +++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/web/src/widgets/map3d/Map3D.tsx b/apps/web/src/widgets/map3d/Map3D.tsx index 625d0cc..a2487b0 100644 --- a/apps/web/src/widgets/map3d/Map3D.tsx +++ b/apps/web/src/widgets/map3d/Map3D.tsx @@ -737,6 +737,11 @@ export function Map3D({ const disposeMercatorOverlay = () => { const current = overlayRef.current; if (!current) return; + try { + current.setProps({ layers: [] } as never); + } catch { + // ignore + } try { map.removeControl(current as never); } catch { @@ -783,17 +788,21 @@ export function Map3D({ const currentProjection = extractProjectionType(map); const shouldSwitchProjection = currentProjection !== next; + if (projection === "globe") { + disposeMercatorOverlay(); + } else { + disposeGlobeDeckLayer(); + } + try { if (shouldSwitchProjection) { map.setProjection({ type: next }); } map.setRenderWorldCopies(next !== "globe"); - if (shouldSwitchProjection) { - if (!cancelled && retries < maxRetries) { - retries += 1; - window.requestAnimationFrame(() => syncProjectionAndDeck()); - return; - } + if (shouldSwitchProjection && currentProjection !== next && !cancelled && retries < maxRetries) { + retries += 1; + window.requestAnimationFrame(() => syncProjectionAndDeck()); + return; } } catch (e) { if (!cancelled && retries < maxRetries) { @@ -804,12 +813,6 @@ export function Map3D({ console.warn("Projection switch failed:", e); } - const oldOverlay = overlayRef.current; - if (projection === "globe" && oldOverlay) { - // Globe mode uses custom MapLibre deck layers and should fully replace Mercator overlays. - disposeMercatorOverlay(); - } - if (projection === "globe") { // Start with a clean globe Deck layer state to avoid partially torn-down renders. disposeGlobeDeckLayer(); @@ -919,8 +922,7 @@ export function Map3D({ if (!map.isStyleLoaded()) return; const disableBathyHeavy = projection === "globe" && baseMap === "enhanced"; const visHeavy = disableBathyHeavy ? "none" : "visible"; - const disableBaseMapSea = projection === "globe"; - const seaVisibility = disableBaseMapSea ? "none" : "visible"; + const seaVisibility = "visible" as const; const seaRegex = /(water|sea|ocean|river|lake|coast|bay)/i; // Globe + our injected bathymetry fill polygons can exceed MapLibre's per-segment vertex limit @@ -940,8 +942,8 @@ export function Map3D({ } } - // Vector basemap water/raster layers can flicker on globe with dense symbols/fills in this stack. - // Hide them only in globe mode and restore on return. + // Vector basemap water layers can be tuned per-style. Keep visible by default, + // only toggling layers that match an explicit water/sea signature. try { for (const layer of map.getStyle().layers || []) { const id = String(layer.id ?? ""); @@ -951,7 +953,7 @@ export function Map3D({ const type = String((layer as { type?: unknown }).type ?? "").toLowerCase(); const isSea = seaRegex.test(id) || seaRegex.test(sourceLayer) || seaRegex.test(source); const isRaster = type === "raster"; - if (!isSea && !isRaster) continue; + if (!isSea) continue; if (!map.getLayer(id)) continue; if (isRaster && id === "seamark") continue; try {