fix(map): Globe 사진 인디케이터 네이티브 레이어 전환
- Globe Deck.gl ScatterplotLayer 아티팩트(파란 막대) 수정 - MapLibre 네이티브 circle 레이어로 사진 인디케이터 구현
This commit is contained in:
부모
e72e2f14f6
커밋
d5a8be3b96
@ -347,32 +347,10 @@ export function useDeckLayers(
|
|||||||
if (!deckTarget) return;
|
if (!deckTarget) return;
|
||||||
|
|
||||||
if (!ENABLE_GLOBE_DECK_OVERLAYS) {
|
if (!ENABLE_GLOBE_DECK_OVERLAYS) {
|
||||||
// Ship photo indicator: 사진 유무 표시 (ScatterplotLayer)
|
// Globe에서는 Deck.gl ScatterplotLayer가 프로젝션 공간 아티팩트(막대)를 유발하므로
|
||||||
const photoLayers: unknown[] = [];
|
// 빈 레이어만 설정. 사진 인디케이터는 Mercator에서만 동작.
|
||||||
if (settings.showShips && overlays.shipPhotos && shipPhotoTargets.length > 0) {
|
|
||||||
photoLayers.push(
|
|
||||||
new ScatterplotLayer<AisTarget>({
|
|
||||||
id: 'ship-photo-indicator',
|
|
||||||
data: shipPhotoTargets,
|
|
||||||
pickable: true,
|
|
||||||
billboard: false,
|
|
||||||
filled: true,
|
|
||||||
stroked: true,
|
|
||||||
radiusUnits: 'pixels',
|
|
||||||
getRadius: 5,
|
|
||||||
getFillColor: [0, 188, 212, 180],
|
|
||||||
getLineColor: [255, 255, 255, 200],
|
|
||||||
lineWidthUnits: 'pixels',
|
|
||||||
getLineWidth: 1,
|
|
||||||
getPosition: (d) => [d.lon, d.lat] as [number, number],
|
|
||||||
onClick: (info: PickingInfo) => {
|
|
||||||
if (info.object) onClickShipPhoto?.((info.object as AisTarget).mmsi);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
deckTarget.setProps({ layers: sanitizeDeckLayerList(photoLayers), getTooltip: undefined, onClick: undefined } as never);
|
deckTarget.setProps({ layers: [], getTooltip: undefined, onClick: undefined } as never);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
@ -439,8 +417,5 @@ export function useDeckLayers(
|
|||||||
toFleetMmsiList,
|
toFleetMmsiList,
|
||||||
touchDeckHoverState,
|
touchDeckHoverState,
|
||||||
legacyHits,
|
legacyHits,
|
||||||
shipPhotoTargets,
|
|
||||||
onClickShipPhoto,
|
|
||||||
overlays.shipPhotos,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,6 +120,7 @@ export function useGlobeShipLayers(
|
|||||||
alarmKind: alarmKind ?? '',
|
alarmKind: alarmKind ?? '',
|
||||||
alarmBadgeLabel: alarmKind ? ALARM_BADGE[alarmKind].label : '',
|
alarmBadgeLabel: alarmKind ? ALARM_BADGE[alarmKind].label : '',
|
||||||
alarmBadgeColor: alarmKind ? ALARM_BADGE[alarmKind].color : '#000',
|
alarmBadgeColor: alarmKind ? ALARM_BADGE[alarmKind].color : '#000',
|
||||||
|
hasPhoto: t.shipImagePath ? 1 : 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
@ -167,13 +168,14 @@ export function useGlobeShipLayers(
|
|||||||
const symbolLiteId = 'ships-globe-lite';
|
const symbolLiteId = 'ships-globe-lite';
|
||||||
const symbolId = 'ships-globe';
|
const symbolId = 'ships-globe';
|
||||||
const labelId = 'ships-globe-label';
|
const labelId = 'ships-globe-label';
|
||||||
|
const photoId = 'ships-globe-photo';
|
||||||
const pulseId = 'ships-globe-alarm-pulse';
|
const pulseId = 'ships-globe-alarm-pulse';
|
||||||
const badgeId = 'ships-globe-alarm-badge';
|
const badgeId = 'ships-globe-alarm-badge';
|
||||||
|
|
||||||
// 레이어를 제거하지 않고 visibility만 'none'으로 설정
|
// 레이어를 제거하지 않고 visibility만 'none'으로 설정
|
||||||
// guardedSetVisibility로 현재 값과 동일하면 호출 생략 (style._changed 방지)
|
// guardedSetVisibility로 현재 값과 동일하면 호출 생략 (style._changed 방지)
|
||||||
const hide = () => {
|
const hide = () => {
|
||||||
for (const id of [badgeId, labelId, symbolId, symbolLiteId, pulseId, outlineId, haloId]) {
|
for (const id of [badgeId, photoId, labelId, symbolId, symbolLiteId, pulseId, outlineId, haloId]) {
|
||||||
guardedSetVisibility(map, id, 'none');
|
guardedSetVisibility(map, id, 'none');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -197,6 +199,7 @@ export function useGlobeShipLayers(
|
|||||||
// → style._changed 방지 → 불필요한 symbol placement 재계산 방지 → 라벨 사라짐 방지
|
// → style._changed 방지 → 불필요한 symbol placement 재계산 방지 → 라벨 사라짐 방지
|
||||||
const visibility: 'visible' | 'none' = projection === 'globe' ? 'visible' : 'none';
|
const visibility: 'visible' | 'none' = projection === 'globe' ? 'visible' : 'none';
|
||||||
const labelVisibility: 'visible' | 'none' = projection === 'globe' && overlays.shipLabels ? 'visible' : 'none';
|
const labelVisibility: 'visible' | 'none' = projection === 'globe' && overlays.shipLabels ? 'visible' : 'none';
|
||||||
|
const photoVisibility: 'visible' | 'none' = projection === 'globe' && overlays.shipPhotos ? 'visible' : 'none';
|
||||||
if (map.getLayer(symbolId) || map.getLayer(symbolLiteId)) {
|
if (map.getLayer(symbolId) || map.getLayer(symbolLiteId)) {
|
||||||
const changed =
|
const changed =
|
||||||
map.getLayoutProperty(symbolId, 'visibility') !== visibility ||
|
map.getLayoutProperty(symbolId, 'visibility') !== visibility ||
|
||||||
@ -208,6 +211,7 @@ export function useGlobeShipLayers(
|
|||||||
if (projection === 'globe') kickRepaint(map);
|
if (projection === 'globe') kickRepaint(map);
|
||||||
}
|
}
|
||||||
guardedSetVisibility(map, labelId, labelVisibility);
|
guardedSetVisibility(map, labelId, labelVisibility);
|
||||||
|
guardedSetVisibility(map, photoId, photoVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 데이터 업데이트는 projectionBusy 중에는 차단
|
// 데이터 업데이트는 projectionBusy 중에는 차단
|
||||||
@ -512,6 +516,35 @@ export function useGlobeShipLayers(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Photo indicator circle (above ship icons, below labels)
|
||||||
|
if (!map.getLayer(photoId)) {
|
||||||
|
needReorder = true;
|
||||||
|
try {
|
||||||
|
map.addLayer(
|
||||||
|
{
|
||||||
|
id: photoId,
|
||||||
|
type: 'circle',
|
||||||
|
source: srcId,
|
||||||
|
filter: ['==', ['get', 'hasPhoto'], 1] as never,
|
||||||
|
layout: { visibility: photoVisibility },
|
||||||
|
paint: {
|
||||||
|
'circle-radius': [
|
||||||
|
'interpolate', ['linear'], ['zoom'],
|
||||||
|
3, 3, 7, 4, 10, 5, 14, 6,
|
||||||
|
] as never,
|
||||||
|
'circle-color': 'rgba(0, 188, 212, 0.7)',
|
||||||
|
'circle-stroke-color': 'rgba(255, 255, 255, 0.8)',
|
||||||
|
'circle-stroke-width': 1,
|
||||||
|
'circle-translate': [8, -8],
|
||||||
|
},
|
||||||
|
} as unknown as LayerSpecification,
|
||||||
|
before,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Ship photo indicator layer add failed:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const labelFilter = [
|
const labelFilter = [
|
||||||
'all',
|
'all',
|
||||||
['!=', ['to-string', ['coalesce', ['get', 'labelName'], '']], ''],
|
['!=', ['to-string', ['coalesce', ['get', 'labelName'], '']], ''],
|
||||||
@ -611,6 +644,7 @@ export function useGlobeShipLayers(
|
|||||||
projection,
|
projection,
|
||||||
settings.showShips,
|
settings.showShips,
|
||||||
overlays.shipLabels,
|
overlays.shipLabels,
|
||||||
|
overlays.shipPhotos,
|
||||||
globeShipGeoJson,
|
globeShipGeoJson,
|
||||||
alarmGeoJson,
|
alarmGeoJson,
|
||||||
mapSyncEpoch,
|
mapSyncEpoch,
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user