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>
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
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 }
|
||
}
|