Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 1x 3x 3x 3x 2x 2x 2x 3x 6x 3x 6x 6x 6x 6x 6x 3x 1x | import {useEffect, useState} from 'react'
import cx from 'classnames'
import PropTypes from 'prop-types'
import {MAX_TRANSITION_TIME_IN_MS, MODIFIERS, SIZES} from './settings.js'
const Circle = ({
baseClassName,
modifier,
percentage,
size,
withAnimation = true,
mainStrokeWidth,
progressStrokeWidth,
strokeLineCap
}) => {
const [currentPercentage, setCurrentPercentage] = useState(percentage)
const [transitionTime, setTransitionTime] = useState(0)
useEffect(
(currentPercentage, percentage) => {
Iif (Math.abs(percentage - currentPercentage) < 5) {
setCurrentPercentage(percentage)
setTransitionTime(0)
} else {
setCurrentPercentage(percentage)
setTransitionTime((MAX_TRANSITION_TIME_IN_MS * percentage) / 100 / 1000)
}
},
[currentPercentage, percentage]
)
const getRadius = () => {
return mainStrokeWidth === progressStrokeWidth
? 50 - mainStrokeWidth / 2
: 50 - Math.max(...[progressStrokeWidth, mainStrokeWidth]) / 2
}
const getPathStyles = ({percentage, strokeWidth}) => {
const radius = getRadius()
const d = `M 50,50 m 0,-${radius}
a ${radius},${radius} 0 1 1 0,${2 * radius}
a ${radius},${radius} 0 1 1 0,-${2 * radius}`
const len = Math.PI * 2 * radius
const style = {
strokeDasharray: `${len}px ${len}px`,
strokeDashoffset: `${((100 - percentage) / 100) * len}px`,
transition: withAnimation ? `stroke-dashoffset ${transitionTime}s ease 0s, stroke ${transitionTime}s ease` : ''
}
return {
d,
style
}
}
return (
<svg
className={cx(`${baseClassName}-circle`, {
[`${baseClassName}-circle--${modifier}`]: !!modifier,
[`${baseClassName}-circle--${size}`]: !!size
})}
viewBox="0 0 100 100"
>
<path
className={cx(`${baseClassName}-trail`, {
[`${baseClassName}-trail--${modifier}`]: !!modifier
})}
{...getPathStyles({percentage: 100, strokeWidth: mainStrokeWidth})}
strokeWidth={mainStrokeWidth}
fillOpacity="0"
/>
<path
className={cx(`${baseClassName}-path`, {
[`${baseClassName}-path--${modifier}`]: !!modifier
})}
{...getPathStyles({percentage, strokeWidth: progressStrokeWidth})}
strokeLinecap={strokeLineCap}
strokeWidth={progressStrokeWidth}
fillOpacity="0"
/>
</svg>
)
}
Circle.propTypes = {
/** Base className to be used in this component */
baseClassName: PropTypes.string.isRequired,
/** CSS modifier for ERROR, LOADING variants */
modifier: PropTypes.oneOf(Object.values(MODIFIERS)),
/** The percentage of the current progress */
percentage: PropTypes.number.isRequired,
/** width of the stroke */
strokeWidth: PropTypes.node.isRequired,
/** boolean to activate/desactivate animations */
withAnimation: PropTypes.bool,
/** The size of the progress stroke, by default it is undefined, it can be "small", "medium" or "large" */
progressStrokeWidth: PropTypes.literal,
/** The size of the main stroke, by default it is undefined, it can be "small", "medium" or "large" */
mainStrokeWidth: PropTypes.literal,
/** The shape of the end of line, it can be "round" or "square" */
strokeLineCap: PropTypes.string,
/** size of the circle [small, large] */
size: PropTypes.oneOf(Object.values(SIZES)).isRequired
}
export default Circle
|