82 lines
2.0 KiB
TypeScript
82 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
|
|
interface SparklineProps {
|
|
data: number[];
|
|
color?: string;
|
|
height?: number;
|
|
width?: number;
|
|
strokeWidth?: number;
|
|
className?: string;
|
|
}
|
|
|
|
export function Sparkline({
|
|
data,
|
|
color = "#00E0A4",
|
|
height = 40,
|
|
width = 120,
|
|
strokeWidth = 2,
|
|
className = "",
|
|
}: SparklineProps) {
|
|
if (!data || data.length < 2) return <div style={{ width, height }} />;
|
|
|
|
const min = Math.min(...data);
|
|
const max = Math.max(...data);
|
|
const range = max - min || 1;
|
|
|
|
const points = data
|
|
.map((val, i) => {
|
|
const x = (i / (data.length - 1)) * width;
|
|
const y = height - ((val - min) / range) * height;
|
|
return `${x},${y}`;
|
|
})
|
|
.join(" ");
|
|
|
|
return (
|
|
<div className={className}>
|
|
<svg
|
|
width={width}
|
|
height={height}
|
|
viewBox={`0 0 ${width} ${height}`}
|
|
className="overflow-visible"
|
|
>
|
|
<defs>
|
|
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
|
<feGaussianBlur stdDeviation="1.5" result="blur" />
|
|
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
|
</filter>
|
|
</defs>
|
|
<polyline
|
|
fill="none"
|
|
stroke={color}
|
|
strokeWidth={strokeWidth}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
points={points}
|
|
filter="url(#glow)"
|
|
style={{ opacity: 0.8 }}
|
|
/>
|
|
{/* Fill Area */}
|
|
<path
|
|
d={`M 0 ${height} L ${points} L ${width} ${height} Z`}
|
|
fill={`url(#gradient-${color.replace("#", "")})`}
|
|
style={{ opacity: 0.1 }}
|
|
/>
|
|
<defs>
|
|
<linearGradient
|
|
id={`gradient-${color.replace("#", "")}`}
|
|
x1="0"
|
|
y1="0"
|
|
x2="0"
|
|
y2="1"
|
|
>
|
|
<stop offset="0%" stopColor={color} />
|
|
<stop offset="100%" stopColor="transparent" />
|
|
</linearGradient>
|
|
</defs>
|
|
</svg>
|
|
</div>
|
|
);
|
|
}
|