fix(globe): keep deck instance across style reloads
This commit is contained in:
부모
b0d51a9490
커밋
0172ed6134
@ -605,6 +605,13 @@ export function Map3D({
|
||||
cancelled = true;
|
||||
controller.abort();
|
||||
|
||||
// If we are unmounting, ensure the globe Deck instance is finalized (style reload would keep it alive).
|
||||
try {
|
||||
globeDeckLayerRef.current?.requestFinalize();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (map) {
|
||||
map.remove();
|
||||
map = null;
|
||||
@ -670,6 +677,7 @@ export function Map3D({
|
||||
const globeLayer = globeDeckLayerRef.current;
|
||||
if (globeLayer && map.getLayer(globeLayer.id)) {
|
||||
try {
|
||||
globeLayer.requestFinalize();
|
||||
map.removeLayer(globeLayer.id);
|
||||
} catch {
|
||||
// ignore
|
||||
@ -728,6 +736,36 @@ export function Map3D({
|
||||
};
|
||||
}, [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
|
||||
useEffect(() => {
|
||||
const map = mapRef.current;
|
||||
|
||||
@ -50,6 +50,7 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
||||
private _deckProps: Partial<DeckProps<MatrixView[]>> = {};
|
||||
private _viewId: string;
|
||||
private _lastMvp: number[] | undefined;
|
||||
private _finalizeOnRemove: boolean = false;
|
||||
|
||||
constructor(opts: { id: string; viewId: string; deckProps?: Partial<DeckProps<MatrixView[]>> }) {
|
||||
this.id = opts.id;
|
||||
@ -61,6 +62,10 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
||||
return this._deck;
|
||||
}
|
||||
|
||||
requestFinalize() {
|
||||
this._finalizeOnRemove = true;
|
||||
}
|
||||
|
||||
setProps(next: Partial<DeckProps<MatrixView[]>>) {
|
||||
this._deckProps = { ...this._deckProps, ...next };
|
||||
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 {
|
||||
this._finalizeOnRemove = false;
|
||||
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[]>({
|
||||
...this._deckProps,
|
||||
// Share MapLibre's WebGL context + canvas (single context).
|
||||
@ -104,15 +123,36 @@ export class MaplibreDeckCustomLayer implements maplibregl.CustomLayerInterface
|
||||
}
|
||||
|
||||
onRemove(): void {
|
||||
this._deck?.finalize();
|
||||
this._deck = null;
|
||||
const deck = this._deck;
|
||||
const map = this._map;
|
||||
this._map = null;
|
||||
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 {
|
||||
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).
|
||||
// For globe, this matrix expects unit-sphere world coordinates (see MapLibre's globe transform).
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user