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 |