fix(globe): keep deck instance across style reloads
This commit is contained in:
부모
b0d51a9490
커밋
0172ed6134
@ -601,14 +601,21 @@ export function Map3D({
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
controller.abort();
|
controller.abort();
|
||||||
|
|
||||||
if (map) {
|
// If we are unmounting, ensure the globe Deck instance is finalized (style reload would keep it alive).
|
||||||
map.remove();
|
try {
|
||||||
map = null;
|
globeDeckLayerRef.current?.requestFinalize();
|
||||||
}
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map) {
|
||||||
|
map.remove();
|
||||||
|
map = null;
|
||||||
|
}
|
||||||
if (overlay) {
|
if (overlay) {
|
||||||
overlay.finalize();
|
overlay.finalize();
|
||||||
overlay = null;
|
overlay = null;
|
||||||
@ -670,6 +677,7 @@ export function Map3D({
|
|||||||
const globeLayer = globeDeckLayerRef.current;
|
const globeLayer = globeDeckLayerRef.current;
|
||||||
if (globeLayer && map.getLayer(globeLayer.id)) {
|
if (globeLayer && map.getLayer(globeLayer.id)) {
|
||||||
try {
|
try {
|
||||||
|
globeLayer.requestFinalize();
|
||||||
map.removeLayer(globeLayer.id);
|
map.removeLayer(globeLayer.id);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
@ -728,6 +736,36 @@ export function Map3D({
|
|||||||
};
|
};
|
||||||
}, [baseMap]);
|
}, [baseMap]);
|
||||||
|
|
||||||
|
// Globe rendering + bathymetry tuning.
|
||||||
|
// Some terrain/hillshade/extrusion effects look unstable under globe and can occlude Deck overlays.
|
||||||
|
useEffect(() => {
|
||||||
|
const map = mapRef.current;
|
||||||
|
if (!map) return;
|
||||||
|
|
||||||
|
const apply = () => {
|
||||||
|
if (!map.isStyleLoaded()) return;
|
||||||
|
const disableBathy3D = projection === "globe" && baseMap === "enhanced";
|
||||||
|
const vis = disableBathy3D ? "none" : "visible";
|
||||||
|
for (const id of ["bathymetry-extrusion", "bathymetry-hillshade"]) {
|
||||||
|
try {
|
||||||
|
if (map.getLayer(id)) map.setLayoutProperty(id, "visibility", vis);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (map.isStyleLoaded()) apply();
|
||||||
|
map.on("style.load", apply);
|
||||||
|
return () => {
|
||||||
|
try {
|
||||||
|
map.off("style.load", apply);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [projection, baseMap]);
|
||||||
|
|
||||||
// seamark toggle
|
// seamark toggle
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
|
|||||||
@ -50,6 +50,7 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
|||||||
private _deckProps: Partial<DeckProps<MatrixView[]>> = {};
|
private _deckProps: Partial<DeckProps<MatrixView[]>> = {};
|
||||||
private _viewId: string;
|
private _viewId: string;
|
||||||
private _lastMvp: number[] | undefined;
|
private _lastMvp: number[] | undefined;
|
||||||
|
private _finalizeOnRemove: boolean = false;
|
||||||
|
|
||||||
constructor(opts: { id: string; viewId: string; deckProps?: Partial<DeckProps<MatrixView[]>> }) {
|
constructor(opts: { id: string; viewId: string; deckProps?: Partial<DeckProps<MatrixView[]>> }) {
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
@ -61,6 +62,10 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
|||||||
return this._deck;
|
return this._deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestFinalize() {
|
||||||
|
this._finalizeOnRemove = true;
|
||||||
|
}
|
||||||
|
|
||||||
setProps(next: Partial<DeckProps<MatrixView[]>>) {
|
setProps(next: Partial<DeckProps<MatrixView[]>>) {
|
||||||
this._deckProps = { ...this._deckProps, ...next };
|
this._deckProps = { ...this._deckProps, ...next };
|
||||||
if (this._deck) this._deck.setProps(this._deckProps as DeckProps<MatrixView[]>);
|
if (this._deck) this._deck.setProps(this._deckProps as DeckProps<MatrixView[]>);
|
||||||
@ -68,8 +73,22 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAdd(map: maplibregl.Map, gl: WebGLRenderingContext | WebGL2RenderingContext): void {
|
onAdd(map: maplibregl.Map, gl: WebGLRenderingContext | WebGL2RenderingContext): void {
|
||||||
|
this._finalizeOnRemove = false;
|
||||||
this._map = map;
|
this._map = map;
|
||||||
|
|
||||||
|
if (this._deck) {
|
||||||
|
// Re-attached after a style change; keep the existing Deck instance so we don't reuse
|
||||||
|
// finalized Layer objects (Deck does not allow that).
|
||||||
|
this._lastMvp = undefined;
|
||||||
|
this._deck.setProps({
|
||||||
|
...this._deckProps,
|
||||||
|
canvas: map.getCanvas(),
|
||||||
|
// Ensure any pending redraw requests trigger a map repaint again.
|
||||||
|
_customRender: () => map.triggerRepaint(),
|
||||||
|
} as DeckProps<MatrixView[]>);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const deck = new Deck<MatrixView[]>({
|
const deck = new Deck<MatrixView[]>({
|
||||||
...this._deckProps,
|
...this._deckProps,
|
||||||
// Share MapLibre's WebGL context + canvas (single context).
|
// Share MapLibre's WebGL context + canvas (single context).
|
||||||
@ -104,15 +123,36 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRemove(): void {
|
onRemove(): void {
|
||||||
this._deck?.finalize();
|
const deck = this._deck;
|
||||||
this._deck = null;
|
const map = this._map;
|
||||||
this._map = null;
|
this._map = null;
|
||||||
this._lastMvp = undefined;
|
this._lastMvp = undefined;
|
||||||
|
|
||||||
|
if (!deck) return;
|
||||||
|
|
||||||
|
if (this._finalizeOnRemove) {
|
||||||
|
deck.finalize();
|
||||||
|
this._deck = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Likely a base style swap; keep Deck instance alive and re-attach in onAdd().
|
||||||
|
// Disable repaint requests until we get re-attached.
|
||||||
|
try {
|
||||||
|
deck.setProps({ _customRender: () => void 0 } as Partial<DeckProps<MatrixView[]>>);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
map?.triggerRepaint();
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(_gl: WebGLRenderingContext | WebGL2RenderingContext, options: maplibregl.CustomRenderMethodInput): void {
|
render(_gl: WebGLRenderingContext | WebGL2RenderingContext, options: maplibregl.CustomRenderMethodInput): void {
|
||||||
const deck = this._deck;
|
const deck = this._deck;
|
||||||
if (!deck) return;
|
if (!deck || !deck.isInitialized) return;
|
||||||
|
|
||||||
// MapLibre gives us a world->clip matrix for the current projection (mercator/globe).
|
// MapLibre gives us a world->clip matrix for the current projection (mercator/globe).
|
||||||
// For globe, this matrix expects unit-sphere world coordinates (see MapLibre's globe transform).
|
// For globe, this matrix expects unit-sphere world coordinates (see MapLibre's globe transform).
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user