64 lines
1.6 KiB
JavaScript
64 lines
1.6 KiB
JavaScript
import React from 'react';
|
|
|
|
const Sparkline = ({ data = [], height = 80, stroke = 'currentColor' }) => {
|
|
if (!data || data.length === 0) return null;
|
|
|
|
const max = Math.max(...data, 1);
|
|
const n = data.length;
|
|
const w = 400;
|
|
|
|
const points = data
|
|
.map((v, i) => {
|
|
const x = n > 1 ? (i / (n - 1)) * w : w / 2;
|
|
const y = height - (v / max) * (height - 8) - 4;
|
|
return `${x.toFixed(1)},${y.toFixed(1)}`;
|
|
})
|
|
.join(' ');
|
|
|
|
const areaPoints = `0,${height} ${points} ${w},${height}`;
|
|
|
|
return (
|
|
<svg
|
|
width='100%'
|
|
height={height}
|
|
viewBox={`0 0 ${w} ${height}`}
|
|
preserveAspectRatio='none'
|
|
>
|
|
<defs>
|
|
<linearGradient id='sg' x1='0%' y1='0%' x2='0%' y2='100%'>
|
|
<stop offset='0%' stopColor={stroke} stopOpacity='0.15' />
|
|
<stop offset='100%' stopColor={stroke} stopOpacity='0' />
|
|
</linearGradient>
|
|
</defs>
|
|
<polygon points={areaPoints} fill='url(#sg)' />
|
|
<polyline
|
|
points={points}
|
|
fill='none'
|
|
stroke={stroke}
|
|
strokeWidth='2.5'
|
|
strokeLinecap='round'
|
|
strokeLinejoin='round'
|
|
vectorEffect='non-scaling-stroke'
|
|
/>
|
|
{data.map((v, i) => {
|
|
const x = n > 1 ? (i / (n - 1)) * w : w / 2;
|
|
const y = height - (v / max) * (height - 8) - 4;
|
|
return (
|
|
<circle
|
|
key={i}
|
|
cx={x.toFixed(1)}
|
|
cy={y.toFixed(1)}
|
|
r='3'
|
|
fill='white'
|
|
stroke={stroke}
|
|
strokeWidth='2'
|
|
vectorEffect='non-scaling-stroke'
|
|
/>
|
|
);
|
|
})}
|
|
</svg>
|
|
);
|
|
};
|
|
|
|
export default Sparkline;
|