"use client"; import { useId } from "react"; interface SparklineProps { data: number[]; width?: number; height?: number; color?: string; fillOpacity?: number; strokeWidth?: number; className?: string; animated?: boolean; } function buildPoints( data: number[], width: number, height: number, strokeWidth: number, ): string { if (data.length === 0) return ""; const padding = strokeWidth; const drawWidth = width - padding * 2; const drawHeight = height - padding * 2; const min = Math.min(...data); const max = Math.max(...data); const range = max - min || 1; // avoid division by zero when all values equal return data .map((v, i) => { const x = data.length === 1 ? width / 2 : padding + (i / (data.length - 1)) * drawWidth; const y = padding + drawHeight - ((v - min) / range) * drawHeight; return `${x},${y}`; }) .join(" "); } function buildAreaPoints( linePoints: string, width: number, height: number, strokeWidth: number, dataLength: number, ): string { if (!linePoints) return ""; const padding = strokeWidth; const drawWidth = width - padding * 2; const bottom = height - padding; const lastX = dataLength === 1 ? width / 2 : padding + drawWidth; const firstX = dataLength === 1 ? width / 2 : padding; return `${linePoints} ${lastX},${bottom} ${firstX},${bottom}`; } export function Sparkline({ data, width = 60, height = 20, color = "currentColor", fillOpacity = 0.1, strokeWidth = 1.5, className, animated = true, }: SparklineProps) { const id = useId(); if (data.length === 0) { return ( ); } const linePoints = buildPoints(data, width, height, strokeWidth); const areaPoints = buildAreaPoints( linePoints, width, height, strokeWidth, data.length, ); // Approximate path length for dash animation const approxLength = width * 2; return ( <> {animated && (