import { useMemo } from "react"; import type { TrafficPoint } from "../(data)/dashboard-mock-data"; type Props = { data: TrafficPoint[]; }; const W = 800; const H = 240; const PAD_L = 46; const PAD_R = 12; const PAD_T = 12; const PAD_B = 28; function formatAxis(value: number) { return value >= 1 ? `${value}G` : `${Math.round(value * 1000)}M`; } export default function TrafficChart({ data }: Props) { const { max, downPath, downArea, upPath, yTicks, xTicks } = useMemo(() => { const plotW = W - PAD_L - PAD_R; const plotH = H - PAD_T - PAD_B; const max = Math.ceil( Math.max(...data.flatMap((p) => [p.up, p.down])), ); const x = (i: number) => PAD_L + (i / (data.length - 1)) * plotW; const y = (v: number) => PAD_T + (1 - v / max) * plotH; const toPath = (key: "up" | "down") => data .map( (p, i) => `${i == 0 ? "M" : "L"}${x(i).toFixed(2)},${y( p[key], ).toFixed(2)}`, ) .join(" "); const downPath = toPath("down"); const upPath = toPath("up"); const baseY = (H - PAD_B).toFixed(2); const downArea = `${downPath} L${x(data.length - 1).toFixed( 2, )},${baseY} L${PAD_L},${baseY} Z`; const yTicks = Array.from({ length: 5 }, (_, i) => { const v = (max / 4) * i; return { v, label: formatAxis(v), y: y(v) }; }); const xTicks: { label: string; x: number }[] = []; for (let i = 0; i < data.length; i += 4) { xTicks.push({ label: data[i]!.label, x: x(i) }); } return { max, downPath, downArea, upPath, yTicks, xTicks }; }, [data]); return ( {yTicks.map((tick, i) => ( {tick.label} ))} {xTicks.map((tick, i) => ( {tick.label} ))} ); }