Files
stats/apps/dashboard/src/components/chart-ssr.tsx
2024-05-01 14:15:31 +02:00

103 lines
2.5 KiB
TypeScript

import * as d3 from 'd3';
export function ChartSSR({
data,
dots = false,
}: {
dots?: boolean;
data: { value: number; date: Date }[];
}) {
if (data.length === 0) {
return null;
}
const xScale = d3
.scaleTime()
.domain([data[0]!.date, data[data.length - 1]!.date])
.range([0, 100]);
const yScale = d3
.scaleLinear()
.domain([0, d3.max(data.map((d) => d.value)) ?? 0])
.range([100, 0]);
const line = d3
.line<(typeof data)[number]>()
.curve(d3.curveMonotoneX)
.x((d) => xScale(d.date))
.y((d) => yScale(d.value));
const area = d3
.area<(typeof data)[number]>()
.curve(d3.curveMonotoneX)
.x((d) => xScale(d.date))
.y0(yScale(0))
.y1((d) => yScale(d.value));
const pathLine = line(data);
const pathArea = area(data);
if (!pathLine) {
return null;
}
return (
<div className="relative h-full w-full">
{/* Chart area */}
<svg className="absolute inset-0 h-full w-full overflow-visible">
<svg
viewBox="0 0 100 100"
className="overflow-visible"
preserveAspectRatio="none"
>
<defs>
<linearGradient
id={`gradient`}
x1="0"
y1="0"
x2="0"
y2="100%"
gradientUnits="userSpaceOnUse"
>
<stop offset="0%" stopColor={'blue'} stopOpacity={0.2}></stop>
<stop offset="50%" stopColor={'blue'} stopOpacity={0.05}></stop>
<stop offset="100%" stopColor={'blue'} stopOpacity={0}></stop>
</linearGradient>
</defs>
{/* Gradient area */}
{pathArea && (
<path
d={pathArea}
fill={`url(#gradient)`}
vectorEffect="non-scaling-stroke"
/>
)}
{/* Line */}
<path
d={pathLine}
fill="none"
className="text-blue-600"
stroke="currentColor"
strokeWidth="2"
vectorEffect="non-scaling-stroke"
/>
{/* Circles */}
{dots &&
data.map((d) => (
<path
key={d.date.toString()}
d={`M ${xScale(d.date)} ${yScale(d.value)} l 0.0001 0`}
vectorEffect="non-scaling-stroke"
strokeWidth="8"
strokeLinecap="round"
fill="none"
stroke="currentColor"
className="text-gray-400"
/>
))}
</svg>
</svg>
</div>
);
}