11"use client" ;
22
33import React from "react" ;
4- import { RadialBarChart , RadialBar , PolarAngleAxis , ResponsiveContainer } from "recharts" ;
54import { useTheme } from "@/contexts/ThemeContext" ;
65
76interface CircleChartProps {
@@ -55,46 +54,56 @@ export default function CircleChart({
5554
5655 const fillColor = getThemeColor ( ) ;
5756
58- const data = [
59- {
60- name : label ,
61- value : chartValue ,
62- fill : fillColor ,
63- } ,
64- ] ;
57+ const renderSVG = ( strokeWidth : number ) => {
58+ // 50 is center (cx, cy), so max radius is 50. We subtract half of strokeWidth to stay inside.
59+ const radius = 50 - strokeWidth / 2 ;
60+ const circumference = 2 * Math . PI * radius ;
61+ const strokeDashoffset = circumference - ( chartValue / 100 ) * circumference ;
62+
63+ // Fallback animation duration if needed
64+ const duration = animationDuration > 0 ? animationDuration : 0 ;
65+ const transitionStyle = duration > 0
66+ ? { transition : `stroke-dashoffset ${ duration } ms ease-out, stroke ${ duration } ms ease-out` }
67+ : { } ;
68+
69+ return (
70+ < svg
71+ viewBox = "0 0 100 100"
72+ className = "w-full h-full transform -rotate-90 overflow-visible"
73+ >
74+ { /* Background Track */ }
75+ < circle
76+ cx = "50"
77+ cy = "50"
78+ r = { radius }
79+ fill = "transparent"
80+ stroke = "currentColor"
81+ strokeWidth = { strokeWidth }
82+ className = "text-muted/20"
83+ />
84+ { /* Progress Arc */ }
85+ < circle
86+ cx = "50"
87+ cy = "50"
88+ r = { radius }
89+ fill = "transparent"
90+ stroke = { fillColor }
91+ strokeWidth = { strokeWidth }
92+ strokeDasharray = { circumference }
93+ strokeDashoffset = { strokeDashoffset }
94+ strokeLinecap = "round"
95+ style = { transitionStyle }
96+ />
97+ </ svg >
98+ ) ;
99+ } ;
65100
66101 // Compact mode for table views
67102 if ( compact ) {
68103 return (
69104 < div className = "flex items-center justify-center" >
70105 < div className = "h-[40px] w-[40px] relative" >
71- < ResponsiveContainer width = "100%" height = "100%" >
72- < RadialBarChart
73- cx = "50%"
74- cy = "50%"
75- innerRadius = "65%"
76- outerRadius = "95%"
77- barSize = { 7 }
78- data = { data }
79- startAngle = { 90 }
80- endAngle = { - 270 }
81- >
82- < PolarAngleAxis
83- type = "number"
84- domain = { [ 0 , 100 ] }
85- angleAxisId = { 0 }
86- tick = { false }
87- />
88- < RadialBar
89- background = { { fill : 'rgba(128, 128, 128, 0.1)' } }
90- dataKey = "value"
91- cornerRadius = { 10 }
92- animationDuration = { animationDuration }
93- animationEasing = "ease-out"
94- />
95- </ RadialBarChart >
96- </ ResponsiveContainer >
97-
106+ { renderSVG ( 12 ) }
98107 { /* Centered Percentage for compact mode */ }
99108 < div className = "absolute inset-0 flex items-center justify-center pointer-events-none" >
100109 < span className = "text-[11px] font-bold text-foreground" >
@@ -110,33 +119,7 @@ export default function CircleChart({
110119 return (
111120 < div className = "flex flex-col items-center justify-center p-2" >
112121 < div className = "h-[90px] w-[90px] relative" >
113- < ResponsiveContainer width = "100%" height = "100%" >
114- < RadialBarChart
115- cx = "50%"
116- cy = "50%"
117- innerRadius = "70%"
118- outerRadius = "95%"
119- barSize = { 8 }
120- data = { data }
121- startAngle = { 90 }
122- endAngle = { - 270 }
123- >
124- < PolarAngleAxis
125- type = "number"
126- domain = { [ 0 , 100 ] }
127- angleAxisId = { 0 }
128- tick = { false }
129- />
130- < RadialBar
131- background = { { fill : 'rgba(128, 128, 128, 0.1)' } }
132- dataKey = "value"
133- cornerRadius = { 10 }
134- animationDuration = { animationDuration }
135- animationEasing = "ease-out"
136- />
137- </ RadialBarChart >
138- </ ResponsiveContainer >
139-
122+ { renderSVG ( 10 ) }
140123 { /* Centered Percentage */ }
141124 < div className = "absolute inset-0 flex items-center justify-center pointer-events-none" >
142125 < span className = "text-base font-bold text-foreground drop-shadow-sm tracking-tight" >
0 commit comments