progress-circle.tsx 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { memo } from 'react'
  2. import cn from '@/utils/classnames'
  3. type ProgressCircleProps = {
  4. className?: string
  5. percentage?: number
  6. size?: number
  7. circleStrokeWidth?: number
  8. circleStrokeColor?: string
  9. circleFillColor?: string
  10. sectorFillColor?: string
  11. }
  12. const ProgressCircle: React.FC<ProgressCircleProps> = ({
  13. className,
  14. percentage = 0,
  15. size = 12,
  16. circleStrokeWidth = 1,
  17. circleStrokeColor = 'stroke-components-progress-brand-border',
  18. circleFillColor = 'fill-components-progress-brand-bg',
  19. sectorFillColor = 'fill-components-progress-brand-progress',
  20. }) => {
  21. const radius = size / 2
  22. const center = size / 2
  23. const angle = (percentage / 101) * 360
  24. const radians = (angle * Math.PI) / 180
  25. const x = center + radius * Math.cos(radians - Math.PI / 2)
  26. const y = center + radius * Math.sin(radians - Math.PI / 2)
  27. const largeArcFlag = percentage > 50 ? 1 : 0
  28. const pathData = `
  29. M ${center},${center}
  30. L ${center},${center - radius}
  31. A ${radius},${radius} 0 ${largeArcFlag} 1 ${x},${y}
  32. Z
  33. `
  34. return (
  35. <svg
  36. width={size + circleStrokeWidth}
  37. height={size + circleStrokeWidth}
  38. viewBox={`0 0 ${size + circleStrokeWidth} ${size + circleStrokeWidth}`}
  39. className={className}
  40. >
  41. <circle
  42. className={cn(
  43. circleFillColor,
  44. circleStrokeColor,
  45. )}
  46. cx={center + circleStrokeWidth / 2}
  47. cy={center + circleStrokeWidth / 2}
  48. r={radius}
  49. strokeWidth={circleStrokeWidth}
  50. />
  51. <path
  52. className={cn(sectorFillColor)}
  53. d={pathData}
  54. transform={`translate(${circleStrokeWidth / 2}, ${circleStrokeWidth / 2})`}
  55. />
  56. </svg>
  57. )
  58. }
  59. export default memo(ProgressCircle)