"use client"; import { useMemo } from "react"; import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts"; import { scaleSymlog } from "d3-scale"; import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig, } from "../ui/chart"; import { ChartMessage } from "./ChartMessage"; import type { HomepageSummary } from "../../lib/homepageSummary"; import { SYMLOG_CONSTANT, compactNumber, symlogTicks, type ChartState, } from "../../lib/homepageChart"; import { buildTimeSeries } from "../../lib/homepageChartData"; // One line per series over a trailing window — the only chart that can carry a // symlog y-axis (lines, not stacked, so a non-additive axis is meaningful). With // one site dwarfing the rest, symlog lifts the small sites off the floor; symlog // (not log) because the daily series is full of zeros. Also renders the indexed // (% growth) value mode, where every series starts at 100. export function MomentumChart({ summary, state, onSelectSeries, }: { summary: HomepageSummary; state: ChartState; onSelectSeries?: (id: string) => void; }) { const { labels, series, max } = useMemo( () => buildTimeSeries(summary, state), [summary, state], ); const config = useMemo(() => { const c: ChartConfig = {}; for (const s of series) c[s.id] = { label: s.label, color: s.color }; return c; }, [series]); const rows = useMemo( () => labels.map((x, i) => { const row: Record = { x }; for (const s of series) row[s.id] = s.values[i] ?? null; return row; }), [labels, series], ); // recharts mutates the scale's domain/range; the constant is what we own. const symlog = useMemo(() => scaleSymlog().constant(SYMLOG_CONSTANT), []); if (series.length === 0 || rows.length === 0) { return ( {state.soloId || state.hidden.size > 0 ? "Every series is hidden — re-enable one from the cards below." : "No data for this view yet."} ); } const isSymlog = state.scale === "symlog"; const domainMax = Math.max(10, max); const ticks = isSymlog ? symlogTicks(domainMax) : undefined; return ( compactNumber(v)} tickLine={false} axisLine={false} width={44} allowDecimals={false} tick={{ fill: "var(--chart-axis)", fontSize: 12 }} /> } /> {series.map((s) => ( onSelectSeries(s.id) : undefined} style={onSelectSeries ? { cursor: "pointer" } : undefined} /> ))} ); }