fix(map): 패널 선택 시 fly-to 복원, 지도 클릭은 제외
- mapInitiatedSelectRef 도입: 지도 클릭 선택과 패널 선택을 구분 - 좌측 패널(선박 목록, 알람 목록) 선택 시 해당 위치로 fly-to - 지도에서 직접 클릭/우클릭 선택 시에는 fly-to 비활성화 - onMapSelectMmsi 래퍼로 지도 내 선택 경로 통합 (Globe+Mercator) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
7bca216c53
커밋
f9da13b694
@ -94,6 +94,7 @@ export function Map3D({
|
||||
const projectionBusyRef = useRef(false);
|
||||
const deckHoverRafRef = useRef<number | null>(null);
|
||||
const deckHoverHasHitRef = useRef(false);
|
||||
const mapInitiatedSelectRef = useRef(false);
|
||||
|
||||
useEffect(() => { baseMapRef.current = baseMap; }, [baseMap]);
|
||||
useEffect(() => { projectionRef.current = projection; }, [projection]);
|
||||
@ -276,6 +277,13 @@ export function Map3D({
|
||||
return out;
|
||||
}, []);
|
||||
|
||||
// 지도 내부 클릭에서의 선택 — fly-to 비활성화 플래그 설정
|
||||
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
||||
const onMapSelectMmsi = useCallback((mmsi: number | null) => {
|
||||
mapInitiatedSelectRef.current = true;
|
||||
onSelectMmsi(mmsi);
|
||||
}, [onSelectMmsi]);
|
||||
|
||||
const onDeckSelectOrHighlight = useCallback(
|
||||
(info: unknown, allowMultiSelect = false) => {
|
||||
const obj = info as {
|
||||
@ -291,12 +299,12 @@ export function Map3D({
|
||||
return;
|
||||
}
|
||||
if (!allowMultiSelect && selectedMmsi === mmsi) {
|
||||
onSelectMmsi(null);
|
||||
onMapSelectMmsi(null);
|
||||
return;
|
||||
}
|
||||
onSelectMmsi(mmsi);
|
||||
onMapSelectMmsi(mmsi);
|
||||
},
|
||||
[hasAuxiliarySelectModifier, onSelectMmsi, onToggleHighlightMmsi, selectedMmsi],
|
||||
[hasAuxiliarySelectModifier, onMapSelectMmsi, onToggleHighlightMmsi, selectedMmsi],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
||||
@ -565,7 +573,7 @@ export function Map3D({
|
||||
{
|
||||
projection, settings, shipData: shipLayerData, shipHighlightSet, shipHoverOverlaySet,
|
||||
shipOverlayLayerData, shipLayerData, shipByMmsi, mapSyncEpoch,
|
||||
onSelectMmsi, onToggleHighlightMmsi, targets: shipLayerData, overlays,
|
||||
onSelectMmsi: onMapSelectMmsi, onToggleHighlightMmsi, targets: shipLayerData, overlays,
|
||||
legacyHits, selectedMmsi, isBaseHighlightedMmsi, hasAuxiliarySelectModifier,
|
||||
onGlobeShipsReady, alarmMmsiMap,
|
||||
},
|
||||
@ -600,7 +608,7 @@ export function Map3D({
|
||||
clearDeckHoverPairs, clearDeckHoverMmsi, clearMapFleetHoverState,
|
||||
setDeckHoverPairs, setDeckHoverMmsi, setMapFleetHoverState,
|
||||
toFleetMmsiList, touchDeckHoverState, hasAuxiliarySelectModifier,
|
||||
onDeckSelectOrHighlight, onSelectMmsi, onToggleHighlightMmsi,
|
||||
onDeckSelectOrHighlight, onSelectMmsi: onMapSelectMmsi, onToggleHighlightMmsi,
|
||||
ensureMercatorOverlay, alarmMmsiMap,
|
||||
},
|
||||
);
|
||||
@ -687,7 +695,7 @@ export function Map3D({
|
||||
|
||||
useFlyTo(
|
||||
mapRef, projectionRef,
|
||||
{ selectedMmsi, shipData, fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom },
|
||||
{ selectedMmsi, shipData, mapInitiatedSelectRef, fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom },
|
||||
);
|
||||
|
||||
// Map ready 콜백 — mapSyncEpoch 초기 증가 시 1회 호출
|
||||
|
||||
@ -9,14 +9,49 @@ export function useFlyTo(
|
||||
opts: {
|
||||
selectedMmsi: number | null;
|
||||
shipData: { mmsi: number; lon: number; lat: number }[];
|
||||
/** true일 때 selectedMmsi fly-to 스킵 (지도 클릭 선택 시) */
|
||||
mapInitiatedSelectRef: MutableRefObject<boolean>;
|
||||
fleetFocusId: string | number | undefined;
|
||||
fleetFocusLon: number | undefined;
|
||||
fleetFocusLat: number | undefined;
|
||||
fleetFocusZoom: number | undefined;
|
||||
},
|
||||
) {
|
||||
const { fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom } = opts;
|
||||
const { selectedMmsi, shipData, mapInitiatedSelectRef, fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom } = opts;
|
||||
|
||||
// 패널(좌측 목록)에서 선택 시 해당 선박 위치로 이동
|
||||
useEffect(() => {
|
||||
// 지도 내부 클릭에서 발생한 선택이면 스킵
|
||||
if (mapInitiatedSelectRef.current) {
|
||||
mapInitiatedSelectRef.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const map = mapRef.current;
|
||||
if (!map || selectedMmsi == null) return;
|
||||
|
||||
const target = shipData.find((t) => t.mmsi === selectedMmsi);
|
||||
if (!target || !Number.isFinite(target.lon) || !Number.isFinite(target.lat)) return;
|
||||
|
||||
const apply = () => {
|
||||
const flyOpts = { center: [target.lon, target.lat] as [number, number], duration: 700 };
|
||||
if (projectionRef.current === 'globe') {
|
||||
map.flyTo(flyOpts);
|
||||
} else {
|
||||
map.easeTo(flyOpts);
|
||||
}
|
||||
};
|
||||
|
||||
if (map.isStyleLoaded()) {
|
||||
apply();
|
||||
return;
|
||||
}
|
||||
|
||||
const stop = onMapStyleReady(map, apply);
|
||||
return () => { stop(); };
|
||||
}, [selectedMmsi, shipData]);
|
||||
|
||||
// 선단 포커스 이동
|
||||
useEffect(() => {
|
||||
const map = mapRef.current;
|
||||
if (!map || fleetFocusLon == null || fleetFocusLat == null || !Number.isFinite(fleetFocusLon) || !Number.isFinite(fleetFocusLat))
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user