A simple donut chart for showing progress. Useful for widget and bento grids.
It will create a new file called donut-chart.tsx inside the components/animata/graphs directory.
donut-chart.tsx
components/animata/graphs
mkdir -p components/animata/graphs && touch components/animata/graphs/donut-chart.tsx
Open the newly created file and paste the following code:
import { ReactNode, useEffect, useState } from "react"; import { cn } from "@/lib/utils"; interface DonutChartProps { size: number; progress: number; trackClassName?: string; progressClassName?: string; circleWidth?: number; progressWidth?: number; rounded?: boolean; className?: string; children?: ReactNode; } export default function DonutChart({ size, progress, progressClassName = "text-green-500", trackClassName = "text-black/10 dark:text-white/10", circleWidth = 16, progressWidth = 16, rounded = true, className, children, }: DonutChartProps) { const [shouldUseValue, setShouldUseValue] = useState(false); useEffect(() => { const timeout = setTimeout(() => { // This is a hack to force the animation to run for the first time. // We can use framer-motion to achieve this but just keeping it simple for now. setShouldUseValue(true); }, 250); return () => clearTimeout(timeout); }, []); const radius = size / 2 - Math.max(progressWidth, circleWidth) / 2; const circumference = Math.PI * radius * 2; const percentage = shouldUseValue ? circumference * ((100 - progress) / 100) : circumference; return ( <div className={className}> <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} version="1.1" xmlns="http://www.w3.org/2000/svg" style={{ transform: "rotate(-90deg)" }} > <circle r={radius} cx={size / 2} cy={size / 2} fill="transparent" stroke="currentColor" strokeWidth={`${circleWidth}px`} strokeDasharray={"10px 0"} strokeDashoffset="0px" className={cn("duration-500", trackClassName)} /> <circle r={radius} cx={size / 2} cy={size / 2} stroke="currentColor" className={cn("duration-500", progressClassName)} strokeWidth={`${progressWidth}px`} strokeLinecap={rounded ? "round" : "butt"} fill="transparent" strokeDasharray={`${circumference}px`} strokeDashoffset={`${percentage}px`} /> </svg> {children} </div> ); }
Built by hari