fix: correlation 동기화 타이밍 수정 + 자동 재생 + 디버그 로그

- loadHistory 완료 후 store.play() 호출 (자동 재생)
- correlation sync effect에 historyActive 의존 추가
  (history 로드 후 이미 도착한 correlation 데이터 재동기화)
- loadHistory 직후 즉시 updateCorrelation 호출 (병렬 로드 대응)
- 디버그 로그: renderFrame 첫 프레임 데이터 상태, correlationByModel 갱신

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
htlee 2026-03-31 08:13:52 +09:00
부모 242fdb8034
커밋 e68f314093
3개의 변경된 파일53개의 추가작업 그리고 7개의 파일을 삭제

파일 보기

@ -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(() => {

파일 보기

@ -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(() => {

파일 보기

@ -217,7 +217,10 @@ export const useGearReplayStore = create<GearReplayState>()(
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<string, GearCorrelationItem[]>();
for (const c of corrData) {
const list = byModel.get(c.modelName) ?? [];
@ -225,6 +228,12 @@ export const useGearReplayStore = create<GearReplayState>()(
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 });
},