"use client"; import { motion } from "motion/react"; import { ChartFrame } from "./chart-frame"; import { linearScale, niceTicks, linePath, smoothPath, areaPath, catColor, type Point } from "@/lib/chart-utils"; export type AreaSeries = { label: string; data: Point[] }; type AreaChartProps = { series: AreaSeries[]; xLabels?: string[]; smooth?: boolean; yMax?: number; width?: number; height?: number; className?: string; }; const M = { top: 16, right: 18, bottom: 34, left: 44 }; /** * AreaChart — filled areas revealed by a bottom-up clip wipe (scaleY origin * bottom), with the line drawn on top. Stacked series cascade by index. */ export function AreaChart({ series, xLabels, smooth = false, yMax, width = 640, height = 380, className, }: AreaChartProps) { const all = series.flatMap((s) => s.data); const xs = all.map((p) => p.x); const ys = all.map((p) => p.y); const xDomain: [number, number] = [Math.min(...xs), Math.max(...xs)]; const yDomain: [number, number] = [Math.min(0, ...ys), yMax ?? Math.max(...ys)]; const sx = linearScale(xDomain, [M.left, width - M.right]); const sy = linearScale(yDomain, [height - M.bottom, M.top]); const baseY = height - M.bottom; const ticks = niceTicks(yDomain[0], yDomain[1], 4); return ( {({ inView }) => ( <> {ticks.map((t) => ( {t} ))} {xLabels?.map((lab, i) => ( {lab} ))} {series.map((s, si) => { const pts = s.data.map((p) => ({ x: sx(p.x), y: sy(p.y) })); const fill = catColor(si); const a = areaPath(pts, baseY, smooth); const d = smooth ? smoothPath(pts) : linePath(pts); const clipId = `area-clip-${si}-${Math.round(pts[0]?.x ?? 0)}`; return ( ); })} )} ); }