Line Chart
Affiche un graphique en courbes pour la visualisation de donnees. Installez Line Chart depuis le registre VLLNT UI avec la CLI shadcn.
Affiche un graphique en courbes pour la visualisation de donnees. Fait partie de la famille data dans VLLNT UI, il est publie comme entree de registre lisible par machine — copiez la source directement dans votre application avec la CLI shadcn et possedez-la, sans dependance d'execution a une bibliotheque de composants.
Installation
Ajoutez Line Chart a votre projet avec la CLI shadcn. La source arrive dans votre code, prete a etre adaptee :
pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/line-chart.jsonSource
"use client";
import * as React from "react";
import { cn } from "../../lib/utils";
type Datum = {
label?: string;
value: number;
};
export type LineChartProps = {
color?: string;
data: Datum[];
gradientId?: string;
height?: number;
strokeWidth?: number;
width?: number;
} & React.HTMLAttributes<HTMLDivElement>;
const DEFAULT_WIDTH = 320;
const DEFAULT_HEIGHT = 140;
const DEFAULT_STROKE_WIDTH = 2;
type ChartDimensions = { height: number; strokeWidth: number; width: number };
function buildCoordinates(data: Datum[], dimensions: ChartDimensions) {
if (data.length === 0) return [];
const { height, strokeWidth, width } = dimensions;
const values = data.map((point) => point.value);
const minValue = Math.min(...values);
const maxValue = Math.max(...values);
const range = maxValue - minValue || 1;
const safeWidth = Math.max(width - strokeWidth * 2, 0);
const safeHeight = Math.max(height - strokeWidth * 2, 0);
return data.map((point, index) => {
const x =
data.length === 1
? strokeWidth + safeWidth / 2
: strokeWidth + (index / (data.length - 1)) * safeWidth;
const ratio = (point.value - minValue) / range;
const y = safeHeight - ratio * safeHeight + strokeWidth;
return { x, y };
});
}
export const LineChart = ({
className,
color = "currentColor",
data,
gradientId = "line-chart-gradient",
height = DEFAULT_HEIGHT,
ref: reference,
strokeWidth = DEFAULT_STROKE_WIDTH,
width = DEFAULT_WIDTH,
...props
}: LineChartProps & { ref?: React.Ref<HTMLDivElement> }) => {
const canvasData = React.useMemo(
() => buildCoordinates(data, { height, strokeWidth, width }),
[data, width, height, strokeWidth],
);
if (canvasData.length === 0) {
return null;
}
const linePath = canvasData
.map((point, index) => `${index === 0 ? "M" : "L"}${point.x},${point.y}`)
.join(" ");
const areaPath =
canvasData.length === 0
? ""
: `M${canvasData[0]?.x ?? 0},${height} ${linePath} L${canvasData.at(-1)?.x ?? 0},${height}Z`;
return (
<div
className={cn(
"rounded-lg border border-border bg-background/40 p-3",
className,
)}
ref={reference}
{...props}
>
<svg
aria-label="Line chart"
className="h-full w-full"
height={height}
role="img"
viewBox={`0 0 ${width} ${height}`}
width={width}
>
<defs>
<linearGradient id={gradientId} x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stopColor={color} stopOpacity="0.45" />
<stop offset="100%" stopColor={color} stopOpacity="0" />
</linearGradient>
</defs>
<path
d={areaPath}
fill={`url(#${gradientId})`}
stroke="none"
vectorEffect="non-scaling-stroke"
/>
<path
d={linePath}
fill="none"
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
vectorEffect="non-scaling-stroke"
/>
</svg>
</div>
);
};
LineChart.displayName = "LineChart";
Stories
Explorez chaque variante et etat dans le Storybook interactif :