Skip to content

Instantly share code, notes, and snippets.

@robinraju
Last active March 5, 2024 16:17
Show Gist options
  • Save robinraju/267bca30b55fb6851f43050dd7988c40 to your computer and use it in GitHub Desktop.
Save robinraju/267bca30b55fb6851f43050dd7988c40 to your computer and use it in GitHub Desktop.
React circular progress bar component
import React from "react"
interface ProgressBarProps {
progress?: number
size?: number
progressColor?: string
trackColor?: string
strokeWidth?: number
showText?: boolean
textColor?: string
fontSize?: number
}
const RadialProgressBar: React.FC<ProgressBarProps> = ({
progress = 0,
size = 125,
progressColor = "#218358",
trackColor = "#E6F6EB",
strokeWidth = 10,
showText = true,
textColor = "#218358",
fontSize = 22,
}) => {
const [textSize, setTextSize] = React.useState({ width: 50, height: 50, fontSize: fontSize })
const textRef = React.useRef<SVGTextElement>(null)
React.useEffect(() => {
if (textRef.current) {
const textRect = textRef.current.getBoundingClientRect()
setTextSize({
width: Math.round(textRect.width),
height: Math.round(textRect.height),
fontSize: textSize.fontSize,
})
}
}, [textRef, textSize.fontSize, progress])
const radius = size / 2 - 10
const circumference = 2 * Math.PI * radius
const offset = circumference * ((100 - progress) / 100)
return (
<div className="flex items-center justify-center">
<svg
width={size}
height={size}
viewBox={`-${size * 0.125} -${size * 0.125} ${size * 1.25} ${size * 1.25}`}
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={trackColor}
strokeWidth={`${strokeWidth}px`}
strokeDasharray={circumference}
strokeDashoffset="0"
></circle>
<circle
r={radius}
cx={size / 2}
cy={size / 2}
fill="transparent"
stroke={progressColor}
strokeWidth={`${strokeWidth}px`}
strokeLinecap="round"
strokeDashoffset={offset}
strokeDasharray={circumference}
></circle>
{showText && (
<text
ref={textRef}
x={`${Math.round(size / 2 - textSize.width / 1.75)}px`}
y={`${Math.round(size / 2 + textSize.height / 3.25)}px`}
fill={textColor}
fontSize={`${textSize.fontSize}px`}
fontWeight="bold"
style={{ transform: `rotate(90deg) translate(0px, -${size - 4}px)` }}
>
{`${progress < 100 ? progress.toFixed(2) : progress}%`}
</text>
)}
</svg>
</div>
)
}
export default RadialProgressBar
<RadialProgressBar progress={33.61} />

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment