fix: guard map style and ship layer ids during rendering
This commit is contained in:
부모
96d8a03f93
커밋
b883c4113b
@ -189,6 +189,12 @@ const MAP_DEFAULT_SHIP_RGB: [number, number, number] = [100, 116, 139];
|
||||
|
||||
const clampNumber = (value: number, minValue: number, maxValue: number) => Math.max(minValue, Math.min(maxValue, value));
|
||||
|
||||
function getLayerId(value: unknown): string | null {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
const candidate = (value as { id?: unknown }).id;
|
||||
return typeof candidate === "string" ? candidate : null;
|
||||
}
|
||||
|
||||
function normalizeAngleDeg(value: number, offset = 0): number {
|
||||
const v = value + offset;
|
||||
return ((v % 360) + 360) % 360;
|
||||
@ -676,7 +682,11 @@ function injectOceanBathymetryLayers(style: StyleSpecification, maptilerKey: str
|
||||
} as unknown as LayerSpecification;
|
||||
|
||||
// Insert before the first symbol layer (keep labels on top), otherwise append.
|
||||
const layers = style.layers as LayerSpecification[];
|
||||
const rawLayers = Array.isArray(style.layers) ? style.layers : [];
|
||||
const layers = rawLayers.filter((layer): layer is LayerSpecification => {
|
||||
if (!layer || typeof layer !== "object") return false;
|
||||
return typeof (layer as { id?: unknown }).id === "string";
|
||||
});
|
||||
const symbolIndex = layers.findIndex((l) => l.type === "symbol");
|
||||
const insertAt = symbolIndex >= 0 ? symbolIndex : layers.length;
|
||||
|
||||
@ -1077,7 +1087,8 @@ export function Map3D({
|
||||
projectionRef.current = projection;
|
||||
}, [projection]);
|
||||
|
||||
const removeLayerIfExists = useCallback((map: maplibregl.Map, layerId: string) => {
|
||||
const removeLayerIfExists = useCallback((map: maplibregl.Map, layerId: string | null | undefined) => {
|
||||
if (!layerId) return;
|
||||
try {
|
||||
if (map.getLayer(layerId)) {
|
||||
map.removeLayer(layerId);
|
||||
@ -1218,9 +1229,10 @@ export function Map3D({
|
||||
onMapStyleReady(map, () => {
|
||||
applyProjection();
|
||||
// Globe deck layer lives inside the style and must be re-added after any style swap.
|
||||
if (projectionRef.current === "globe" && globeDeckLayerRef.current && !map!.getLayer(globeDeckLayerRef.current.id)) {
|
||||
const deckLayer = globeDeckLayerRef.current;
|
||||
if (projectionRef.current === "globe" && deckLayer && !map!.getLayer(deckLayer.id)) {
|
||||
try {
|
||||
map!.addLayer(globeDeckLayerRef.current);
|
||||
map!.addLayer(deckLayer);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
@ -1431,13 +1443,14 @@ export function Map3D({
|
||||
}
|
||||
|
||||
const layer = globeDeckLayerRef.current;
|
||||
if (layer && map.isStyleLoaded() && !map.getLayer(layer.id)) {
|
||||
const layerId = layer?.id;
|
||||
if (layer && layerId && map.isStyleLoaded() && !map.getLayer(layerId)) {
|
||||
try {
|
||||
map.addLayer(layer);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (!map.getLayer(layer.id) && !cancelled && retries < maxRetries) {
|
||||
if (!map.getLayer(layerId) && !cancelled && retries < maxRetries) {
|
||||
retries += 1;
|
||||
window.requestAnimationFrame(() => syncProjectionAndDeck());
|
||||
return;
|
||||
@ -1554,7 +1567,7 @@ export function Map3D({
|
||||
const style = map.getStyle();
|
||||
const styleLayers = style && Array.isArray(style.layers) ? style.layers : [];
|
||||
for (const layer of styleLayers) {
|
||||
const id = String(layer.id ?? "");
|
||||
const id = getLayerId(layer);
|
||||
if (!id) continue;
|
||||
const sourceLayer = String((layer as Record<string, unknown>)["source-layer"] ?? "").toLowerCase();
|
||||
const source = String((layer as { source?: unknown }).source ?? "").toLowerCase();
|
||||
@ -1933,7 +1946,7 @@ export function Map3D({
|
||||
console.warn("Ship icon image setup failed:", e);
|
||||
}
|
||||
|
||||
const globeShipData = targets.filter((t) => isFiniteNumber(t.lat) && isFiniteNumber(t.lon));
|
||||
const globeShipData = shipData;
|
||||
const geojson: GeoJSON.FeatureCollection<GeoJSON.Point> = {
|
||||
type: "FeatureCollection",
|
||||
features: globeShipData.map((t) => {
|
||||
@ -1956,7 +1969,7 @@ export function Map3D({
|
||||
const iconSize14 = clampNumber(0.72 * sizeScale * selectedScale, 0.45, 2.1);
|
||||
return {
|
||||
type: "Feature",
|
||||
id: t.mmsi,
|
||||
...(isFiniteNumber(t.mmsi) ? { id: Math.trunc(t.mmsi) } : {}),
|
||||
geometry: { type: "Point", coordinates: [t.lon, t.lat] },
|
||||
properties: {
|
||||
mmsi: t.mmsi,
|
||||
@ -2890,7 +2903,7 @@ export function Map3D({
|
||||
}, [projection, overlays.pairRange, pairLinks, mapSyncEpoch, hoveredShipSignature, hoveredPairSignature, hoveredFleetSignature, isHighlightedPair]);
|
||||
|
||||
const shipData = useMemo(() => {
|
||||
return targets.filter((t) => isFiniteNumber(t.lat) && isFiniteNumber(t.lon));
|
||||
return targets.filter((t) => isFiniteNumber(t.lat) && isFiniteNumber(t.lon) && isFiniteNumber(t.mmsi));
|
||||
}, [targets]);
|
||||
|
||||
const shipByMmsi = useMemo(() => {
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user