import { useEffect, useRef, useState } from "react"; import type { PathPoint } from "../api"; import { projectTracks, toPath } from "./geo"; export interface RadarTrack { points: PathPoint[]; color: string; label: string; dashed?: boolean; } const NARROW_WIDTH_THRESHOLD = 380; const NARROW_HORIZONTAL_PADDING = 16; const LEGEND_RESERVED_HEIGHT = 26; const MIN_RADAR_DIM = 220; const DEFAULT_RADAR_DIM = 380; export default function RadarPlot({ tracks, size }: { tracks: RadarTrack[]; size?: number }) { const ref = useRef(null); const [autoSize, setAutoSize] = useState(DEFAULT_RADAR_DIM); useEffect(() => { if (size != null || !ref.current) return; const node = ref.current; const observer = new ResizeObserver((entries) => { for (const entry of entries) { const { width, height } = entry.contentRect; if (width <= 0 || height <= 0) continue; const widthCap = width < NARROW_WIDTH_THRESHOLD ? width - NARROW_HORIZONTAL_PADDING : width; const next = Math.max(MIN_RADAR_DIM, Math.min(widthCap, height - LEGEND_RESERVED_HEIGHT)); setAutoSize(next); } }); observer.observe(node); return () => observer.disconnect(); }, [size]); const dim = size ?? autoSize; const projected = projectTracks( tracks.map((track) => track.points), dim, dim, ); const center = dim / 2; const maxRadius = dim / 2 - 8; return (
{[0.25, 0.5, 0.75, 1].map((ratio) => ( ))} {tracks.map((track, index) => ( ))} {tracks.map((track, index) => projected[index].length ? ( ) : null, )}
{tracks.map((track) => ( {track.dashed ? "- - " : "___ "} {track.label} ))}
); }