signal-batch/frontend/src/features/vessel-tracks/hooks/useVesselTracks.ts
htlee ed0f3056b1 feat: Ship-GIS 기능 이관 — 최근위치/선박항적/뷰포트 리플레이
dark(ship-gis) 프로젝트의 맵 기반 3대 기능을 API 탐색기에 이관.
Feature 폴더 모듈화 구조로 타 프로젝트 재활용 가능하게 구성.

Phase 1: vessel-map 공유 모듈 (Deck.gl 9 + Zustand 5 + STOMP)
Phase 2: 최근 위치 (30초 폴링 + IconLayer + 선종 필터 + 팝업)
Phase 3: 선박 항적 (MMSI 조회 + PathLayer + 타임라인 보간)
Phase 4: 뷰포트 리플레이 (STOMP WebSocket 청크 + TripsLayer 애니메이션)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 15:19:21 +09:00

53 lines
1.7 KiB
TypeScript
Raw Blame 히스토리

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useCallback } from 'react'
import { gisApi, type VesselTrackResult } from '../../../api/gisApi'
import { useTrackStore } from '../stores/trackStore'
import type { TrackSegment } from '../../vessel-map'
/** API 응답 → 내부 TrackSegment 변환 */
function toTrackSegment(r: VesselTrackResult): TrackSegment {
return {
vesselId: r.vesselId,
nationalCode: r.nationalCode,
shipKindCode: r.shipKindCode,
shipName: r.shipName,
geometry: r.geometry as [number, number][],
// 백엔드가 문자열 배열로 전송 → 숫자 ms 변환
timestampsMs: r.timestamps.map((t) => {
const n = Number(t)
// 초 단위(10자리)면 ×1000, ms 단위(13자리)면 그대로
return n < 1e12 ? n * 1000 : n
}),
speeds: r.speeds,
totalDistance: r.totalDistance,
avgSpeed: r.avgSpeed,
maxSpeed: r.maxSpeed,
pointCount: r.pointCount,
}
}
/** 선박 항적 조회 훅 */
export function useVesselTracks() {
const setTracks = useTrackStore((s) => s.setTracks)
const setLoading = useTrackStore((s) => s.setLoading)
const clearTracks = useTrackStore((s) => s.clearTracks)
const fetchTracks = useCallback(
async (mmsiList: string[], startTime: string, endTime: string) => {
setLoading(true)
try {
const data = await gisApi.getVesselTracks(mmsiList, startTime, endTime)
const segments = data.map(toTrackSegment)
setTracks(segments)
} catch (err) {
console.error('[useVesselTracks] fetch failed:', err)
clearTracks()
} finally {
setLoading(false)
}
},
[setTracks, setLoading, clearTracks],
)
return { fetchTracks, clearTracks }
}