develop #30
@ -94,6 +94,7 @@ export function Map3D({
|
|||||||
const projectionBusyRef = useRef(false);
|
const projectionBusyRef = useRef(false);
|
||||||
const deckHoverRafRef = useRef<number | null>(null);
|
const deckHoverRafRef = useRef<number | null>(null);
|
||||||
const deckHoverHasHitRef = useRef(false);
|
const deckHoverHasHitRef = useRef(false);
|
||||||
|
const mapInitiatedSelectRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => { baseMapRef.current = baseMap; }, [baseMap]);
|
useEffect(() => { baseMapRef.current = baseMap; }, [baseMap]);
|
||||||
useEffect(() => { projectionRef.current = projection; }, [projection]);
|
useEffect(() => { projectionRef.current = projection; }, [projection]);
|
||||||
@ -276,6 +277,13 @@ export function Map3D({
|
|||||||
return out;
|
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(
|
const onDeckSelectOrHighlight = useCallback(
|
||||||
(info: unknown, allowMultiSelect = false) => {
|
(info: unknown, allowMultiSelect = false) => {
|
||||||
const obj = info as {
|
const obj = info as {
|
||||||
@ -291,12 +299,12 @@ export function Map3D({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!allowMultiSelect && selectedMmsi === mmsi) {
|
if (!allowMultiSelect && selectedMmsi === mmsi) {
|
||||||
onSelectMmsi(null);
|
onMapSelectMmsi(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onSelectMmsi(mmsi);
|
onMapSelectMmsi(mmsi);
|
||||||
},
|
},
|
||||||
[hasAuxiliarySelectModifier, onSelectMmsi, onToggleHighlightMmsi, selectedMmsi],
|
[hasAuxiliarySelectModifier, onMapSelectMmsi, onToggleHighlightMmsi, selectedMmsi],
|
||||||
);
|
);
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
// eslint-disable-next-line react-hooks/preserve-manual-memoization
|
||||||
@ -565,7 +573,7 @@ export function Map3D({
|
|||||||
{
|
{
|
||||||
projection, settings, shipData: shipLayerData, shipHighlightSet, shipHoverOverlaySet,
|
projection, settings, shipData: shipLayerData, shipHighlightSet, shipHoverOverlaySet,
|
||||||
shipOverlayLayerData, shipLayerData, shipByMmsi, mapSyncEpoch,
|
shipOverlayLayerData, shipLayerData, shipByMmsi, mapSyncEpoch,
|
||||||
onSelectMmsi, onToggleHighlightMmsi, targets: shipLayerData, overlays,
|
onSelectMmsi: onMapSelectMmsi, onToggleHighlightMmsi, targets: shipLayerData, overlays,
|
||||||
legacyHits, selectedMmsi, isBaseHighlightedMmsi, hasAuxiliarySelectModifier,
|
legacyHits, selectedMmsi, isBaseHighlightedMmsi, hasAuxiliarySelectModifier,
|
||||||
onGlobeShipsReady, alarmMmsiMap,
|
onGlobeShipsReady, alarmMmsiMap,
|
||||||
},
|
},
|
||||||
@ -600,7 +608,7 @@ export function Map3D({
|
|||||||
clearDeckHoverPairs, clearDeckHoverMmsi, clearMapFleetHoverState,
|
clearDeckHoverPairs, clearDeckHoverMmsi, clearMapFleetHoverState,
|
||||||
setDeckHoverPairs, setDeckHoverMmsi, setMapFleetHoverState,
|
setDeckHoverPairs, setDeckHoverMmsi, setMapFleetHoverState,
|
||||||
toFleetMmsiList, touchDeckHoverState, hasAuxiliarySelectModifier,
|
toFleetMmsiList, touchDeckHoverState, hasAuxiliarySelectModifier,
|
||||||
onDeckSelectOrHighlight, onSelectMmsi, onToggleHighlightMmsi,
|
onDeckSelectOrHighlight, onSelectMmsi: onMapSelectMmsi, onToggleHighlightMmsi,
|
||||||
ensureMercatorOverlay, alarmMmsiMap,
|
ensureMercatorOverlay, alarmMmsiMap,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -687,7 +695,7 @@ export function Map3D({
|
|||||||
|
|
||||||
useFlyTo(
|
useFlyTo(
|
||||||
mapRef, projectionRef,
|
mapRef, projectionRef,
|
||||||
{ selectedMmsi, shipData, fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom },
|
{ selectedMmsi, shipData, mapInitiatedSelectRef, fleetFocusId, fleetFocusLon, fleetFocusLat, fleetFocusZoom },
|
||||||
);
|
);
|
||||||
|
|
||||||
// Map ready 콜백 — mapSyncEpoch 초기 증가 시 1회 호출
|
// Map ready 콜백 — mapSyncEpoch 초기 증가 시 1회 호출
|
||||||
|
|||||||
@ -9,14 +9,49 @@ export function useFlyTo(
|
|||||||
opts: {
|
opts: {
|
||||||
selectedMmsi: number | null;
|
selectedMmsi: number | null;
|
||||||
shipData: { mmsi: number; lon: number; lat: number }[];
|
shipData: { mmsi: number; lon: number; lat: number }[];
|
||||||
|
/** true일 때 selectedMmsi fly-to 스킵 (지도 클릭 선택 시) */
|
||||||
|
mapInitiatedSelectRef: MutableRefObject<boolean>;
|
||||||
fleetFocusId: string | number | undefined;
|
fleetFocusId: string | number | undefined;
|
||||||
fleetFocusLon: number | undefined;
|
fleetFocusLon: number | undefined;
|
||||||
fleetFocusLat: number | undefined;
|
fleetFocusLat: number | undefined;
|
||||||
fleetFocusZoom: 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(() => {
|
useEffect(() => {
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
if (!map || fleetFocusLon == null || fleetFocusLat == null || !Number.isFinite(fleetFocusLon) || !Number.isFinite(fleetFocusLat))
|
if (!map || fleetFocusLon == null || fleetFocusLat == null || !Number.isFinite(fleetFocusLon) || !Number.isFinite(fleetFocusLat))
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user