"use client"; import { motion } from "framer-motion"; import { useEffect, useState } from "react"; interface RadarChartProps { data: { label: string; score: number; maxScore?: number; }[]; size?: number; } export default function RadarChart({ data, size = 300 }: RadarChartProps) { const [isAnimated, setIsAnimated] = useState(false); const center = size / 2; const radius = (size / 2) - 60; // Increased padding for labels const angleStep = (Math.PI * 2) / data.length; useEffect(() => { setIsAnimated(true); }, []); // Calculate points for the polygon const getPoint = (value: number, index: number) => { const angle = index * angleStep - Math.PI / 2; const r = (value / 100) * radius; return { x: center + r * Math.cos(angle), y: center + r * Math.sin(angle) }; }; // Create polygon points string const polygonPoints = data .map((item, i) => { const point = getPoint(isAnimated ? item.score : 0, i); return `${point.x},${point.y}`; }) .join(' '); // Grid levels const gridLevels = [20, 40, 60, 80, 100]; return (
{/* Grid circles */} {gridLevels.map((level) => ( ))} {/* Axis lines */} {data.map((_, i) => { const angle = i * angleStep - Math.PI / 2; const x2 = center + radius * Math.cos(angle); const y2 = center + radius * Math.sin(angle); return ( ); })} {/* Data polygon */} {/* Data points */} {data.map((item, i) => { const point = getPoint(item.score, i); return ( ); })} {/* Labels */} {data.map((item, i) => { const angle = i * angleStep - Math.PI / 2; const labelRadius = radius + 40; // Increased label distance const x = center + labelRadius * Math.cos(angle); const y = center + labelRadius * Math.sin(angle); // Better text anchor logic based on quadrant let textAnchor = "middle"; let dy = 0; // Left side if (x < center - 20) { textAnchor = "end"; } // Right side else if (x > center + 20) { textAnchor = "start"; } // Top if (y < center - 20) { dy = -5; } // Bottom else if (y > center + 20) { dy = 5; } return ( {/* Background for better readability */} {item.label} {/* Score value */} {item.score}% ); })} {/* Legend */}
80-100%
60-79%
<60%
); }