import type { Race } from "../api"; import { formatRaceDate, isCloseDistance, parseFinishTimeToSeconds } from "../lib"; type PaceTrendChartProps = { races: Race[]; distanceKm: number; }; /** * Minimal SVG sparkline: finish time (minutes) over chronological completed races * at the selected distance. Lower time = higher point (better). */ export function PaceTrendChart(props: PaceTrendChartProps): JSX.Element { const { races, distanceKm } = props; const series = races .filter( (race) => race.status === "completed" && isCloseDistance(race.distanceKm, distanceKm) && parseFinishTimeToSeconds(race.finishTime) != null, ) .sort( (a, b) => new Date(`${a.date}T00:00:00`).getTime() - new Date(`${b.date}T00:00:00`).getTime(), ) .map((race) => { const seconds = parseFinishTimeToSeconds(race.finishTime)!; return { race, minutes: seconds / 60 }; }); if (series.length < 2) { return (
Нужно минимум два завершённых старта с временем на выбранной дистанции.
); } const minutes = series.map((s) => s.minutes); const minM = Math.min(...minutes); const maxM = Math.max(...minutes); const range = maxM - minM || 1; const n = series.length; const pad = 4; const w = 100; const h = 36; const innerW = w - pad * 2; const innerH = h - pad * 2; const points = series .map((s, i) => { const x = pad + (n === 1 ? innerW / 2 : (i / (n - 1)) * innerW); const norm = (maxM - s.minutes) / range; const y = pad + (1 - norm) * innerH; return `${x},${y}`; }) .join(" "); const last = series[series.length - 1]!; return (Последний пункт: {formatRaceDate(last.race.date)} — {last.race.finishTime} ( {last.minutes.toFixed(1)} мин)