react-circle-timer-tungln
Version:
Lightweight React countdown timer circle component with color and progress animation based on SVG
153 lines (138 loc) • 3.59 kB
JSX
import React, { useState, useEffect, forwardRef } from "react";
const ReactCircleTimer = (props, ref) => {
const {
size = 80,
strokeBgColor = "#ccc",
strokeWidth = 10,
strokeColor = "red",
seconds = 30,
prefixTime = "",
autoPlay = false,
colorsTime = {},
} = props;
const [countdown, setCountdown] = useState(seconds * 1000);
const [isPlaying, setIsPlaying] = useState(false);
const milliseconds = seconds * 1000;
const radius = size / 2;
const circumference = size * Math.PI;
const strokeDashoffset = () => {
return circumference - (countdown / milliseconds) * circumference;
};
useEffect(() => {
let interval = null;
if (isPlaying || autoPlay) {
interval = setInterval(() => {
setCountdown((prevCountdown) => {
if (prevCountdown <= 0 && !autoPlay) {
clearInterval(interval);
setIsPlaying(false);
setCountdown(seconds * 1000);
}
if (prevCountdown <= 0 && autoPlay) {
setCountdown(seconds * 1000);
}
return prevCountdown - 10;
});
}, 10);
}
return () => {
clearInterval(interval);
};
}, [isPlaying, autoPlay]);
const stopTimer = () => {
setIsPlaying(false);
};
useEffect(() => {
if (ref && ref.current) {
ref.current = { startTimer, stopTimer, resumeTimer, resetTimer };
}
}, []);
const startTimer = () => {
setCountdown(seconds * 1000);
setIsPlaying(true);
};
const resumeTimer = () => {
setIsPlaying(true);
};
const resetTimer = () => {
setIsPlaying(false);
setCountdown(seconds * 1000);
};
const countdownSizeStyles = {
height: size,
width: size,
};
const textStyles = {
color: strokeColor,
fontSize: size * 0.3,
};
const timer = (countdown / 1000).toFixed();
return (
<div>
<div
style={{
...styles.countdownContainer,
...countdownSizeStyles,
}}
>
<p style={{ ...textStyles, ...colorsTime }}>
{timer} {prefixTime}
</p>
<svg style={styles.svg}>
<circle
cx={radius}
cy={radius}
r={radius}
fill="none"
stroke={strokeBgColor}
strokeWidth={strokeWidth}
></circle>
</svg>
<svg style={styles.svg}>
<circle
strokeDasharray={circumference}
strokeDashoffset={strokeDashoffset() || 0}
r={radius}
cx={radius}
cy={radius}
fill="none"
strokeLinecap="round"
stroke={strokeColor}
strokeWidth={strokeWidth}
></circle>
</svg>
</div>
</div>
);
};
export default forwardRef(ReactCircleTimer);
const styles = {
countdownContainer: {
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "relative",
margin: "auto",
},
svg: {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
transform: "rotateY(-180deg) rotateZ(-90deg)",
overflow: "visible",
},
button: {
fontSize: "16px",
padding: "10px 30px",
margin: "10px auto 30px",
display: "block",
backgroundColor: "#4d4d4d",
color: "lightgray",
border: "none",
cursor: "pointer",
outline: 0,
borderRadius: "5px",
},
};