diff --git a/frontend/src/components/korea/FleetClusterLayer.tsx b/frontend/src/components/korea/FleetClusterLayer.tsx index 4d3f3ec..e3f6690 100644 --- a/frontend/src/components/korea/FleetClusterLayer.tsx +++ b/frontend/src/components/korea/FleetClusterLayer.tsx @@ -74,9 +74,13 @@ export function FleetClusterLayer({ ships, analysisMap: analysisMapProp, onShipS const history = await fetchGroupHistory(groupKey, 12); const sorted = history.reverse(); const filled = fillGapFrames(sorted); - useGearReplayStore.getState().loadHistory( - filled, correlationTracks, correlationData, enabledModels, enabledVessels, - ); + const store = useGearReplayStore.getState(); + store.loadHistory(filled, correlationTracks, correlationData, enabledModels, enabledVessels); + // correlation 데이터가 이미 로드된 경우 즉시 동기화 + if (correlationData.length > 0 || correlationTracks.length > 0) { + store.updateCorrelation(correlationData, correlationTracks); + } + store.play(); }; const closeHistory = useCallback(() => { @@ -97,12 +101,13 @@ export function FleetClusterLayer({ ships, analysisMap: analysisMapProp, onShipS useGearReplayStore.getState().setHoveredMmsi(hoveredTarget?.mmsi ?? null); }, [hoveredTarget]); - // ── correlation 데이터 → store 동기화 (비동기 로드 후 반영) ── + // ── correlation 데이터 → store 동기화 ── + // historyActive 의존: history 로드 후 이미 도착한 correlation 데이터 반영 useEffect(() => { - if (correlationData.length > 0 || correlationTracks.length > 0) { + if (historyActive && (correlationData.length > 0 || correlationTracks.length > 0)) { useGearReplayStore.getState().updateCorrelation(correlationData, correlationTracks); } - }, [correlationData, correlationTracks]); + }, [correlationData, correlationTracks, historyActive]); // ── ESC 키 ── useEffect(() => { diff --git a/frontend/src/hooks/useGearReplayLayers.ts b/frontend/src/hooks/useGearReplayLayers.ts index c28b65b..fcf819c 100644 --- a/frontend/src/hooks/useGearReplayLayers.ts +++ b/frontend/src/hooks/useGearReplayLayers.ts @@ -69,6 +69,9 @@ export function useGearReplayLayers( // ── renderFrame ────────────────────────────────────────────────────────── + // 디버그 로그 (첫 프레임에서만 출력) + const debugLoggedRef = useRef(false); + const renderFrame = useCallback(() => { if (historyFrames.length === 0) { replayLayerRef.current = []; @@ -80,6 +83,22 @@ export function useGearReplayLayers( const ct = state.currentTime; const st = state.startTime; + // 디버그: 첫 프레임에서 데이터 상태 출력 + if (!debugLoggedRef.current) { + debugLoggedRef.current = true; + console.log('[GearReplay] renderFrame 시작:', { + historyFrames: state.historyFrames.length, + correlationByModel: state.correlationByModel.size, + modelNames: [...state.correlationByModel.keys()], + correlationTripsData: correlationTripsData.length, + enabledModels: [...enabledModels], + enabledVessels: enabledVessels.size, + }); + for (const [mn, items] of state.correlationByModel) { + console.log(` [${mn}] ${items.length}건 (vessels: ${items.filter(c => c.targetType === 'VESSEL').length}, gear: ${items.filter(c => c.targetType !== 'VESSEL').length})`); + } + } + // Find current frame const { index: frameIdx, cursor } = findFrameAtTime(state.frameTimes, ct, cursorRef.current); cursorRef.current = cursor; @@ -449,6 +468,11 @@ export function useGearReplayLayers( } } + // 디버그: 연관 선박 렌더링 상태 + if (corrPositions.length > 0 && !debugLoggedRef.current) { + console.log('[GearReplay] corrPositions:', corrPositions.length, 'operationalPolygons:', layers.filter(l => l.id?.toString().startsWith('replay-op-')).length); + } + replayLayerRef.current = layers; requestRender(); }, [ @@ -458,6 +482,14 @@ export function useGearReplayLayers( replayLayerRef, requestRender, ]); + // correlationByModel이 갱신되면 디버그 로그 리셋 (새 데이터 도착 확인) + useEffect(() => { + if (correlationByModel.size > 0) { + debugLoggedRef.current = false; + console.log('[GearReplay] correlationByModel 갱신:', correlationByModel.size, '모델', [...correlationByModel.keys()]); + } + }, [correlationByModel]); + // ── zustand.subscribe effect (currentTime → renderFrame) ───────────────── useEffect(() => { diff --git a/frontend/src/stores/gearReplayStore.ts b/frontend/src/stores/gearReplayStore.ts index b91a8e9..b1e63c6 100644 --- a/frontend/src/stores/gearReplayStore.ts +++ b/frontend/src/stores/gearReplayStore.ts @@ -217,7 +217,10 @@ export const useGearReplayStore = create()( updateCorrelation: (corrData, corrTracks) => { const state = get(); - if (state.historyFrames.length === 0) return; + if (state.historyFrames.length === 0) { + console.log('[GearReplayStore] updateCorrelation 스킵: historyFrames 비어있음'); + return; + } const byModel = new Map(); for (const c of corrData) { const list = byModel.get(c.modelName) ?? []; @@ -225,6 +228,12 @@ export const useGearReplayStore = create()( byModel.set(c.modelName, list); } const corrTrips = buildCorrelationTripsData(corrTracks, state.startTime); + console.log('[GearReplayStore] updateCorrelation:', { + corrData: corrData.length, + models: [...byModel.keys()], + corrTrips: corrTrips.length, + corrTracks: corrTracks.length, + }); set({ correlationByModel: byModel, correlationTripsData: corrTrips }); },