"use client";
import {
PolarAngleAxis,
RadialBar,
RadialBarChart,
ResponsiveContainer,
Tooltip,
} from "recharts";
export interface TooltipItem {
name: string;
value: number;
color?: string;
}
interface RadialChartProps {
percentage: number;
label?: string;
color?: string;
backgroundColor?: string;
height?: number;
innerRadius?: number;
outerRadius?: number;
startAngle?: number;
endAngle?: number;
hasDots?: boolean;
tooltipData?: TooltipItem[];
}
const CustomTooltip = ({ active, payload }: any) => {
if (!active || !payload || !payload.length) return null;
const tooltipItems = payload[0]?.payload?.tooltipData;
if (
!tooltipItems ||
!Array.isArray(tooltipItems) ||
tooltipItems.length === 0
)
return null;
return (
{tooltipItems.map((item: TooltipItem, index: number) => (
{item.name}
{item.value}%
))}
);
};
export function RadialChart({
percentage,
color = "var(--bg-pass-primary)",
backgroundColor = "var(--bg-neutral-tertiary)",
height = 250,
innerRadius = 60,
outerRadius = 100,
startAngle = 90,
endAngle = -270,
hasDots = false,
tooltipData,
}: RadialChartProps) {
// Calculate the real barSize based on the difference
const barSize = outerRadius - innerRadius;
const data = [
{
value: percentage,
tooltipData,
},
];
const middleRadius = innerRadius;
const viewBoxWidth = height;
const viewBoxHeight = height;
const centerX = viewBoxWidth / 2;
const centerY = viewBoxHeight / 2;
const arcAngle = Math.abs(startAngle - endAngle);
const dotSpacing = 20; // 4px dot + 8px space
const arcCircumference = (arcAngle / 360) * (2 * Math.PI * middleRadius);
const numberOfDots = Math.floor(arcCircumference / dotSpacing);
return (
{tooltipData && (
}
wrapperStyle={{ zIndex: 1000 }}
cursor={false}
/>
)}
{hasDots &&
Array.from({ length: numberOfDots })
.slice(1, -1)
.map((_, i) => {
// Calculate the angle for this point
// Adjust the index since we now start from 1
const angleProgress = (i + 1) / (numberOfDots - 1 || 1);
const currentAngle =
startAngle - angleProgress * (startAngle - endAngle);
// Show dots only in the background part (after the percentage value)
const valueAngleEnd =
startAngle - (percentage / 100) * (startAngle - endAngle);
if (currentAngle > valueAngleEnd) {
return null; // Don't show dots in the part with value
}
const currentAngleRad = (currentAngle * Math.PI) / 180;
// Calculate absolute position in the viewBox
const x = centerX + middleRadius * Math.cos(currentAngleRad) + 22;
const y = centerY - middleRadius * Math.sin(currentAngleRad);
return (
);
})}
{percentage}%
);
}