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>
71 lines
1.7 KiB
TypeScript
71 lines
1.7 KiB
TypeScript
import { useRef, useEffect, useCallback } from 'react'
|
|
import { MapboxOverlay } from '@deck.gl/mapbox'
|
|
import type { Layer } from '@deck.gl/core'
|
|
import type maplibregl from 'maplibre-gl'
|
|
|
|
/**
|
|
* MapLibre + Deck.gl MapboxOverlay 통합 관리 훅
|
|
*
|
|
* - MapboxOverlay 생성/제거 라이프사이클
|
|
* - setLayers()로 Deck.gl 레이어 동적 업데이트
|
|
* - pickObject()로 클릭/호버 인터랙션
|
|
*/
|
|
export function useMapInstance(map: maplibregl.Map | null) {
|
|
const overlayRef = useRef<MapboxOverlay | null>(null)
|
|
|
|
// Overlay 초기화 + 정리
|
|
useEffect(() => {
|
|
if (!map) return
|
|
|
|
const initOverlay = () => {
|
|
if (overlayRef.current) return
|
|
|
|
const overlay = new MapboxOverlay({
|
|
interleaved: false,
|
|
layers: [],
|
|
})
|
|
map.addControl(overlay)
|
|
overlayRef.current = overlay
|
|
}
|
|
|
|
if (map.loaded()) {
|
|
initOverlay()
|
|
} else {
|
|
map.on('load', initOverlay)
|
|
}
|
|
|
|
return () => {
|
|
map.off('load', initOverlay)
|
|
if (overlayRef.current) {
|
|
try {
|
|
map.removeControl(overlayRef.current)
|
|
} catch {
|
|
// 맵이 이미 제거된 경우
|
|
}
|
|
overlayRef.current.finalize()
|
|
overlayRef.current = null
|
|
}
|
|
}
|
|
}, [map])
|
|
|
|
/** Deck.gl 레이어 배열 업데이트 */
|
|
const setLayers = useCallback((layers: Layer[]) => {
|
|
overlayRef.current?.setProps({ layers })
|
|
}, [])
|
|
|
|
/** 특정 좌표의 객체 피킹 */
|
|
const pickObject = useCallback(
|
|
(x: number, y: number, layerIds?: string[]) => {
|
|
if (!overlayRef.current) return null
|
|
try {
|
|
return overlayRef.current.pickObject({ x, y, layerIds }) ?? null
|
|
} catch {
|
|
return null
|
|
}
|
|
},
|
|
[],
|
|
)
|
|
|
|
return { overlayRef, setLayers, pickObject }
|
|
}
|