fix(map): harden globe projection switch and overlay teardown
This commit is contained in:
부모
15378ed7ff
커밋
0ffadb2e66
@ -126,6 +126,16 @@ function onMapStyleReady(map: maplibregl.Map, callback: () => void) {
|
||||
};
|
||||
}
|
||||
|
||||
function extractProjectionType(map: maplibregl.Map): MapProjectionId | undefined {
|
||||
const projection = map.getProjection?.();
|
||||
if (!projection || typeof projection !== "object") return undefined;
|
||||
|
||||
const rawType = (projection as { type?: unknown; name?: unknown }).type ?? (projection as { type?: unknown; name?: unknown }).name;
|
||||
if (rawType === "globe") return "globe";
|
||||
if (rawType === "mercator") return "mercator";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
|
||||
const clampNumber = (value: number, minValue: number, maxValue: number) => Math.max(minValue, Math.min(maxValue, value));
|
||||
@ -724,9 +734,38 @@ export function Map3D({
|
||||
let retries = 0;
|
||||
const maxRetries = 18;
|
||||
|
||||
const getCurrentProjection = () => {
|
||||
const projectionConfig = map.getProjection?.();
|
||||
return projectionConfig && "type" in projectionConfig ? (projectionConfig.type as MapProjectionId | undefined) : undefined;
|
||||
const disposeMercatorOverlay = () => {
|
||||
const current = overlayRef.current;
|
||||
if (!current) return;
|
||||
try {
|
||||
map.removeControl(current as never);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
current.finalize();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
overlayRef.current = null;
|
||||
};
|
||||
|
||||
const disposeGlobeDeckLayer = () => {
|
||||
const current = globeDeckLayerRef.current;
|
||||
if (!current) return;
|
||||
if (map.getLayer(current.id)) {
|
||||
try {
|
||||
map.removeLayer(current.id);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
try {
|
||||
current.requestFinalize();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
globeDeckLayerRef.current = null;
|
||||
};
|
||||
|
||||
const syncProjectionAndDeck = () => {
|
||||
@ -741,11 +780,21 @@ export function Map3D({
|
||||
}
|
||||
|
||||
const next = projection;
|
||||
const currentProjection = extractProjectionType(map);
|
||||
const shouldSwitchProjection = currentProjection !== next;
|
||||
|
||||
try {
|
||||
if (getCurrentProjection() !== next) {
|
||||
if (shouldSwitchProjection) {
|
||||
map.setProjection({ type: next });
|
||||
}
|
||||
map.setRenderWorldCopies(next !== "globe");
|
||||
if (shouldSwitchProjection) {
|
||||
if (!cancelled && retries < maxRetries) {
|
||||
retries += 1;
|
||||
window.requestAnimationFrame(() => syncProjectionAndDeck());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (!cancelled && retries < maxRetries) {
|
||||
retries += 1;
|
||||
@ -758,25 +807,12 @@ export function Map3D({
|
||||
const oldOverlay = overlayRef.current;
|
||||
if (projection === "globe" && oldOverlay) {
|
||||
// Globe mode uses custom MapLibre deck layers and should fully replace Mercator overlays.
|
||||
try {
|
||||
oldOverlay.finalize();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
overlayRef.current = null;
|
||||
disposeMercatorOverlay();
|
||||
}
|
||||
|
||||
if (projection === "globe") {
|
||||
// Ensure any stale layer from old mode is dropped then re-added on this projection.
|
||||
if (globeDeckLayerRef.current) {
|
||||
try {
|
||||
if (map.getLayer(globeDeckLayerRef.current.id)) {
|
||||
map.removeLayer(globeDeckLayerRef.current.id);
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
// Start with a clean globe Deck layer state to avoid partially torn-down renders.
|
||||
disposeGlobeDeckLayer();
|
||||
|
||||
if (!globeDeckLayerRef.current) {
|
||||
globeDeckLayerRef.current = new MaplibreDeckCustomLayer({
|
||||
@ -801,15 +837,7 @@ export function Map3D({
|
||||
}
|
||||
} else {
|
||||
// Tear down globe custom layer (if present), restore MapboxOverlay interleaved.
|
||||
const globeLayer = globeDeckLayerRef.current;
|
||||
if (globeLayer && map.getLayer(globeLayer.id)) {
|
||||
try {
|
||||
globeLayer.requestFinalize();
|
||||
map.removeLayer(globeLayer.id);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
disposeGlobeDeckLayer();
|
||||
|
||||
if (!overlayRef.current) {
|
||||
try {
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user