react-simple-circular-progress
Version:
A simple circular progress indicator component for React.
62 lines (61 loc) • 4.2 kB
JavaScript
import React from 'react';
const CircularProgress = (props) => {
const { style = {}, size, percent = 1, gapAngle = 90, backgroundBarColor = '#F5F5F4', progressBarWidth = 15, progressBarColor = '#2C40F3', progressBarOpacity = 1, progressFillColor = 'none', scaleAngles, scaleWidth = 2, scaleColor = '#2a2a2a', scaleOpacity = 0.1, svgExtraProps = {}, children, } = props;
const halfSrokeWidth = progressBarWidth / 2;
const radius = (size - progressBarWidth) / 2;
const circumference = 2 * Math.PI * radius;
const gapLength = (gapAngle / 360) * circumference;
const addRotateAngle = halfSrokeWidth / (circumference / 360);
const isLinearGradientColor = typeof progressBarColor !== 'string';
const renderBackgroundCircle = () => {
const progressLength = circumference - gapLength;
const finalProgressLength = progressLength < progressBarWidth ? 1 : progressLength - progressBarWidth;
const dashArray = `${finalProgressLength}, ${circumference - finalProgressLength}`;
return (React.createElement("circle", { cx: size / 2, cy: size / 2, r: radius, stroke: backgroundBarColor, strokeWidth: progressBarWidth, strokeDasharray: dashArray, strokeDashoffset: 0, fill: 'none', strokeLinecap: 'round', transform: `rotate(${90 + gapAngle / 2 + addRotateAngle} ${size / 2} ${size / 2})` }));
};
const renderCircularProgress = () => {
const progressLength = (percent / 100) * (circumference - gapLength);
const finalProgressLength = progressLength < progressBarWidth ? 1 : progressLength - progressBarWidth;
const dashArray = `${finalProgressLength}, ${circumference - finalProgressLength}`;
return (React.createElement("circle", { cx: size / 2, cy: size / 2, r: radius, stroke: isLinearGradientColor ? 'url(#progressGrad)' : progressBarColor, strokeWidth: progressBarWidth, strokeDasharray: dashArray, strokeDashoffset: 0, fill: progressFillColor, strokeLinecap: 'round', strokeOpacity: progressBarOpacity, transform: `rotate(${90 + gapAngle / 2 + addRotateAngle} ${size / 2} ${size / 2})` }));
};
const renderScaleAngles = () => {
if (!scaleAngles)
return null;
return scaleAngles.map((angle, index) => {
const radian = (angle * Math.PI) / 180;
const halfSrokeWidth = progressBarWidth / 2;
const x1 = size / 2 + (radius + halfSrokeWidth) * Math.cos(radian);
const y1 = size / 2 + (radius + halfSrokeWidth) * Math.sin(radian);
const x2 = size / 2 + (radius - halfSrokeWidth) * Math.cos(radian);
const y2 = size / 2 + (radius - halfSrokeWidth) * Math.sin(radian);
return (React.createElement("line", { key: index, x1: x1, y1: y1, x2: x2, y2: y2, stroke: scaleColor, strokeWidth: scaleWidth, strokeOpacity: scaleOpacity }));
});
};
const renderDefs = () => {
if (!isLinearGradientColor)
return null;
const linearGradientProps = progressBarColor.reduce((acc, cur, index) => {
acc[`x${index + 1}`] = `${cur[0]}%`;
acc[`y${index + 1}`] = '0%';
return acc;
}, {});
return (React.createElement("defs", null,
React.createElement("linearGradient", Object.assign({ id: 'progressGrad' }, linearGradientProps), progressBarColor.map((item, index) => (React.createElement("stop", { key: index, offset: `${item[0]}%`, stopColor: item[1], stopOpacity: '1' }))))));
};
const renderContent = () => {
if (typeof children === 'function') {
return children({ percent });
}
return children;
};
const containerStyle = Object.assign({ width: size, height: size, position: 'relative', display: 'flex', justifyContent: 'center', alignItems: 'center' }, style);
return (React.createElement("div", { style: containerStyle },
React.createElement("svg", Object.assign({ viewBox: `0 0 ${size} ${size}`, width: size, height: size }, svgExtraProps),
renderDefs(),
renderBackgroundCircle(),
renderCircularProgress(),
renderScaleAngles()),
renderContent()));
};
export default CircularProgress;