Fixed radial chart
This commit is contained in:
@@ -1,20 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {
|
|
||||||
Label,
|
|
||||||
PolarGrid,
|
|
||||||
PolarRadiusAxis,
|
|
||||||
RadialBar,
|
|
||||||
RadialBarChart,
|
|
||||||
} from "recharts";
|
|
||||||
import { ChartContainer, type ChartConfig } from "@/components/ui/chart";
|
|
||||||
|
|
||||||
const chartConfig = {
|
|
||||||
value: {
|
|
||||||
label: "Value",
|
|
||||||
},
|
|
||||||
} satisfies ChartConfig;
|
|
||||||
|
|
||||||
export default function RadialChart({
|
export default function RadialChart({
|
||||||
value,
|
value,
|
||||||
children,
|
children,
|
||||||
@@ -22,57 +7,70 @@ export default function RadialChart({
|
|||||||
value: number;
|
value: number;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const chartData = [{ value, fill: "var(--color-chart-1)" }];
|
const radius = 42;
|
||||||
|
const stroke = 10;
|
||||||
|
const circumference = 2 * Math.PI * radius;
|
||||||
|
|
||||||
|
const TRIM_ANGLE = 80;
|
||||||
|
const ARC_ANGLE = 360 - TRIM_ANGLE;
|
||||||
|
|
||||||
|
const progress = Math.min(Math.max(value, 0), 100);
|
||||||
|
const arcLength = circumference * (ARC_ANGLE / 360);
|
||||||
|
const offset = arcLength * (1 - progress / 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartContainer config={chartConfig} className="w-full aspect-square">
|
<div className="w-full aspect-square">
|
||||||
<RadialBarChart
|
<svg viewBox="0 0 100 100" className="w-full h-full">
|
||||||
data={chartData}
|
{/* background arc */}
|
||||||
startAngle={230 - 360 * (value / 100)}
|
<circle
|
||||||
endAngle={230}
|
cx="50"
|
||||||
innerRadius={80}
|
cy="50"
|
||||||
outerRadius={110}
|
r={radius}
|
||||||
>
|
fill="none"
|
||||||
<PolarGrid
|
stroke="var(--muted)"
|
||||||
gridType="circle"
|
strokeWidth={stroke}
|
||||||
radialLines={false}
|
strokeLinecap="round"
|
||||||
stroke="none"
|
strokeDasharray={`${arcLength} ${circumference}`}
|
||||||
className="first:fill-muted last:fill-background"
|
strokeDashoffset={0}
|
||||||
polarRadius={[86, 74]}
|
transform="rotate(130 50 50)"
|
||||||
/>
|
/>
|
||||||
<RadialBar dataKey="value" background cornerRadius={10} />
|
|
||||||
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
|
{/* progress arc */}
|
||||||
<Label
|
<circle
|
||||||
content={({ viewBox }) => {
|
cx="50"
|
||||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
cy="50"
|
||||||
return (
|
r={radius}
|
||||||
<text
|
fill="none"
|
||||||
x={viewBox.cx}
|
stroke="var(--color-chart-1)"
|
||||||
y={viewBox.cy}
|
strokeWidth={stroke}
|
||||||
textAnchor="middle"
|
strokeLinecap="round"
|
||||||
dominantBaseline="middle"
|
strokeDasharray={`${arcLength} ${circumference}`}
|
||||||
>
|
strokeDashoffset={offset}
|
||||||
<tspan
|
transform="rotate(130 50 50)"
|
||||||
x={viewBox.cx}
|
/>
|
||||||
y={viewBox.cy}
|
|
||||||
className="fill-foreground text-xl font-bold"
|
{/* center text */}
|
||||||
>
|
<text
|
||||||
{chartData[0].value.toFixed(1)}%
|
x="50"
|
||||||
</tspan>
|
y="50"
|
||||||
<tspan
|
textAnchor="middle"
|
||||||
x={viewBox.cx}
|
dominantBaseline="middle"
|
||||||
y={(viewBox.cy || 0) + 24}
|
className="fill-foreground text-sm font-bold"
|
||||||
className="fill-muted-foreground"
|
>
|
||||||
>
|
{value.toFixed(1)}%
|
||||||
{children}
|
</text>
|
||||||
</tspan>
|
|
||||||
</text>
|
{children && (
|
||||||
);
|
<text
|
||||||
}
|
x="50"
|
||||||
}}
|
y="67"
|
||||||
/>
|
textAnchor="middle"
|
||||||
</PolarRadiusAxis>
|
className="fill-muted-foreground text-xs"
|
||||||
</RadialBarChart>
|
>
|
||||||
</ChartContainer>
|
{children}
|
||||||
|
</text>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user