/** * 항적분석 호버 툴팁 컴포넌트 * - 선박 기본 정보 (선종, 선명, 신호원) * - 시간순 방문 이력 (구역 무관, entryTimestamp 정렬) */ import { useMemo } from 'react'; import { useAreaSearchStore } from '../stores/areaSearchStore'; import { ZONE_COLORS } from '../types/areaSearch.types'; import { getShipKindName, getSignalSourceName } from '../../tracking/types/trackQuery.types'; import './AreaSearchTooltip.scss'; const OFFSET_X = 14; const OFFSET_Y = -20; /** nationalCode → 국기 SVG URL */ function getNationalFlagUrl(nationalCode) { if (!nationalCode) return null; return `/ship/image/small/${nationalCode}.svg`; } export function formatTimestamp(ms) { if (!ms) return '-'; const d = new Date(ms); const pad = (n) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; } export function formatPosition(pos) { if (!pos || pos.length < 2) return null; const lon = pos[0]; const lat = pos[1]; const latDir = lat >= 0 ? 'N' : 'S'; const lonDir = lon >= 0 ? 'E' : 'W'; return `${Math.abs(lat).toFixed(4)}\u00B0${latDir} ${Math.abs(lon).toFixed(4)}\u00B0${lonDir}`; } export default function AreaSearchTooltip() { const tooltip = useAreaSearchStore((s) => s.areaSearchTooltip); const tracks = useAreaSearchStore((s) => s.tracks); const hitDetails = useAreaSearchStore((s) => s.hitDetails); const zones = useAreaSearchStore((s) => s.zones); const zoneMap = useMemo(() => { const map = new Map(); zones.forEach((z, idx) => { map.set(z.id, z); map.set(z.name, z); map.set(idx, z); map.set(String(idx), z); }); return map; }, [zones]); if (!tooltip) return null; const { vesselId, x, y } = tooltip; const track = tracks.find((t) => t.vesselId === vesselId); if (!track) return null; const hits = hitDetails[vesselId] || []; const kindName = getShipKindName(track.shipKindCode); const sourceName = getSignalSourceName(track.sigSrcCd); const flagUrl = getNationalFlagUrl(track.nationalCode); // 시간순 정렬 (구역 무관) const sortedHits = [...hits].sort((a, b) => a.entryTimestamp - b.entryTimestamp); return (
{kindName} {flagUrl && ( 국기 { e.target.style.display = 'none'; }} /> )} {track.shipName || track.targetId || '-'}
{sourceName}
{sortedHits.length > 0 && (
{sortedHits.map((hit, idx) => { const zone = zoneMap.get(hit.polygonId); const zoneColor = zone ? (ZONE_COLORS[zone.colorIndex]?.label || '#ffd43b') : '#adb5bd'; const zoneName = zone ? `${zone.name}구역` : (hit.polygonName ? `${hit.polygonName}구역` : '구역'); const visitLabel = hit.visitIndex > 1 || sortedHits.filter((h) => h.polygonId === hit.polygonId).length > 1 ? `(${hit.visitIndex}차)` : ''; const entryPos = formatPosition(hit.entryPosition); const exitPos = formatPosition(hit.exitPosition); return (
{idx + 1}. {zoneName} {visitLabel && ( {visitLabel} )}
{idx + 1}-IN {formatTimestamp(hit.entryTimestamp)} {entryPos && ( {entryPos} )}
{idx + 1}-OUT {formatTimestamp(hit.exitTimestamp)} {exitPos && ( {exitPos} )}
); })}
)}
); }