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));
|
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 {
|
function normalizeAngleDeg(value: number, offset = 0): number {
|
||||||
const v = value + offset;
|
const v = value + offset;
|
||||||
return ((v % 360) + 360) % 360;
|
return ((v % 360) + 360) % 360;
|
||||||
@ -676,7 +682,11 @@ function injectOceanBathymetryLayers(style: StyleSpecification, maptilerKey: str
|
|||||||
} as unknown as LayerSpecification;
|
} as unknown as LayerSpecification;
|
||||||
|
|
||||||
// Insert before the first symbol layer (keep labels on top), otherwise append.
|
// 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 symbolIndex = layers.findIndex((l) => l.type === "symbol");
|
||||||
const insertAt = symbolIndex >= 0 ? symbolIndex : layers.length;
|
const insertAt = symbolIndex >= 0 ? symbolIndex : layers.length;
|
||||||
|
|
||||||
@ -1077,7 +1087,8 @@ export function Map3D({
|
|||||||
projectionRef.current = projection;
|
projectionRef.current = projection;
|
||||||
}, [projection]);
|
}, [projection]);
|
||||||
|
|
||||||
const removeLayerIfExists = useCallback((map: maplibregl.Map, layerId: string) => {
|
const removeLayerIfExists = useCallback((map: maplibregl.Map, layerId: string | null | undefined) => {
|
||||||
|
if (!layerId) return;
|
||||||
try {
|
try {
|
||||||
if (map.getLayer(layerId)) {
|
if (map.getLayer(layerId)) {
|
||||||
map.removeLayer(layerId);
|
map.removeLayer(layerId);
|
||||||
@ -1218,9 +1229,10 @@ export function Map3D({
|
|||||||
onMapStyleReady(map, () => {
|
onMapStyleReady(map, () => {
|
||||||
applyProjection();
|
applyProjection();
|
||||||
// Globe deck layer lives inside the style and must be re-added after any style swap.
|
// 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 {
|
try {
|
||||||
map!.addLayer(globeDeckLayerRef.current);
|
map!.addLayer(deckLayer);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@ -1431,13 +1443,14 @@ export function Map3D({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const layer = globeDeckLayerRef.current;
|
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 {
|
try {
|
||||||
map.addLayer(layer);
|
map.addLayer(layer);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
if (!map.getLayer(layer.id) && !cancelled && retries < maxRetries) {
|
if (!map.getLayer(layerId) && !cancelled && retries < maxRetries) {
|
||||||
retries += 1;
|
retries += 1;
|
||||||
window.requestAnimationFrame(() => syncProjectionAndDeck());
|
window.requestAnimationFrame(() => syncProjectionAndDeck());
|
||||||
return;
|
return;
|
||||||
@ -1554,7 +1567,7 @@ export function Map3D({
|
|||||||
const style = map.getStyle();
|
const style = map.getStyle();
|
||||||
const styleLayers = style && Array.isArray(style.layers) ? style.layers : [];
|
const styleLayers = style && Array.isArray(style.layers) ? style.layers : [];
|
||||||
for (const layer of styleLayers) {
|
for (const layer of styleLayers) {
|
||||||
const id = String(layer.id ?? "");
|
const id = getLayerId(layer);
|
||||||
if (!id) continue;
|
if (!id) continue;
|
||||||
const sourceLayer = String((layer as Record<string, unknown>)["source-layer"] ?? "").toLowerCase();
|
const sourceLayer = String((layer as Record<string, unknown>)["source-layer"] ?? "").toLowerCase();
|
||||||
const source = String((layer as { source?: unknown }).source ?? "").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);
|
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> = {
|
const geojson: GeoJSON.FeatureCollection<GeoJSON.Point> = {
|
||||||
type: "FeatureCollection",
|
type: "FeatureCollection",
|
||||||
features: globeShipData.map((t) => {
|
features: globeShipData.map((t) => {
|
||||||
@ -1956,7 +1969,7 @@ export function Map3D({
|
|||||||
const iconSize14 = clampNumber(0.72 * sizeScale * selectedScale, 0.45, 2.1);
|
const iconSize14 = clampNumber(0.72 * sizeScale * selectedScale, 0.45, 2.1);
|
||||||
return {
|
return {
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
id: t.mmsi,
|
...(isFiniteNumber(t.mmsi) ? { id: Math.trunc(t.mmsi) } : {}),
|
||||||
geometry: { type: "Point", coordinates: [t.lon, t.lat] },
|
geometry: { type: "Point", coordinates: [t.lon, t.lat] },
|
||||||
properties: {
|
properties: {
|
||||||
mmsi: t.mmsi,
|
mmsi: t.mmsi,
|
||||||
@ -2890,7 +2903,7 @@ export function Map3D({
|
|||||||
}, [projection, overlays.pairRange, pairLinks, mapSyncEpoch, hoveredShipSignature, hoveredPairSignature, hoveredFleetSignature, isHighlightedPair]);
|
}, [projection, overlays.pairRange, pairLinks, mapSyncEpoch, hoveredShipSignature, hoveredPairSignature, hoveredFleetSignature, isHighlightedPair]);
|
||||||
|
|
||||||
const shipData = useMemo(() => {
|
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]);
|
}, [targets]);
|
||||||
|
|
||||||
const shipByMmsi = useMemo(() => {
|
const shipByMmsi = useMemo(() => {
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user