So this a countdown timer and when I press a button the countdown start by this line : timePassed = timePassed = 1;
Now the problem is if I press another button to reset the timer the fuctions start stacking on each other and the seconds becomes faster.
i need so that all buttons work and resets the timepassed so they don't stacking...
const FULL_DASH_ARRAY = 283;
const WARNING_THRESHOLD = 10;
const ALERT_THRESHOLD = 5;
const COLOR_CODES = {
info: {
color: "green"
},
warning: {
color: "orange",
threshold: WARNING_THRESHOLD
},
alert: {
color: "red",
threshold: ALERT_THRESHOLD
}
};
var TIME_LIMIT = 0;
let timePassed = 0;
let timeLeft = TIME_LIMIT;
let timerInterval = null;
let remainingPathColor = COLOR_CODES.info.color;
document.getElementById("app").innerHTML = `
<div >
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g >
<circle cx="50" cy="50" r="45"></circle>
<path
id="base-timer-path-remaining"
stroke-dasharray="283"
hljs-subst">${remainingPathColor}"
d="
M 50, 50
m -45, 0
a 45,45 0 1,0 90,0
a 45,45 0 1,0 -90,0
"
></path>
</g>
</svg>
<span id="base-timer-label" >${formatTime(
timeLeft
)}</span>
</div>
`;
function onTimesUp() {
clearInterval(timerInterval);
}
function formatTime(time) {
const minutes = Math.floor(time / 60);
let seconds = time % 60;
if (seconds < 10) {
seconds = `0${seconds}`;
}
return `${minutes}:${seconds}`;
}
function setRemainingPathColor(timeLeft) {
const { alert, warning, info } = COLOR_CODES;
if (timeLeft <= alert.threshold) {
document
.getElementById("base-timer-path-remaining")
.classList.remove(warning.color);
document
.getElementById("base-timer-path-remaining")
.classList.add(alert.color);
} else if (timeLeft <= warning.threshold) {
document
.getElementById("base-timer-path-remaining")
.classList.remove(info.color);
document
.getElementById("base-timer-path-remaining")
.classList.add(warning.color);
}
}
function calculateTimeFraction() {
const rawTimeFraction = timeLeft / TIME_LIMIT;
return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
}
function setCircleDasharray() {
const circleDasharray = `${(
calculateTimeFraction() * FULL_DASH_ARRAY
).toFixed(0)} 283`;
document
.getElementById("base-timer-path-remaining")
.setAttribute("stroke-dasharray", circleDasharray);
}
function timer15(){
TIME_LIMIT = 901;
timePassed = 0;
timeLeft = TIME_LIMIT;
timerInterval = null;
remainingPathColor = COLOR_CODES.info.color;
timerInterval = setInterval(() => {
timePassed = timePassed = 0;
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer30(){
TIME_LIMIT = 1801;
timePassed = 0;
timeLeft = TIME_LIMIT;
timerInterval = null;
remainingPathColor = COLOR_CODES.info.color;
timerInterval = setInterval(() => {
timePassed = timePassed = 0;
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer45(){
TIME_LIMIT = 2701;
timePassed = 0;
timeLeft = TIME_LIMIT;
timerInterval = null;
remainingPathColor = COLOR_CODES.info.color;
timerInterval = setInterval(() => {
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer60(){
TIME_LIMIT = 3601;
timePassed = 0;
timeLeft = TIME_LIMIT;
timerInterval = null;
remainingPathColor = COLOR_CODES.info.color;
timerInterval = setInterval(() => {
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
body {
font-family: sans-serif;
display: grid;
height: 100vh;
place-items: center;
}
.base-timer {
position: relative;
width: 300px;
height: 300px;
}
.base-timer__svg {
transform: scaleX(-1);
}
.base-timer__circle {
fill: none;
stroke: none;
}
.base-timer__path-elapsed {
stroke-width: 7px;
stroke: grey;
}
.base-timer__path-remaining {
stroke-width: 7px;
stroke-linecap: round;
transform: rotate(90deg);
transform-origin: center;
transition: 1s linear all;
fill-rule: nonzero;
stroke: currentColor;
}
.base-timer__path-remaining.green {
color: rgb(65, 184, 131);
}
.base-timer__path-remaining.orange {
color: orange;
}
.base-timer__path-remaining.red {
color: red;
}
.base-timer__label {
position: absolute;
width: 300px;
height: 300px;
top: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 48px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="timer.css">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<input type="button" onclick="timer15()" value="15 min">
<input type="button" onclick="timer30()" value="30 min">
<input type="button" onclick="timer45()" value="45 min">
<input type="button" onclick="timer60()" value="60 min">
<script src="timer.js"></script>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
In each timerfunction you are setting timerInterval = null
. This will not stop or clear the previously registered interval rather only remove its reference from the timerInterval
variable. So you have to clear interval first before setting the new time interval.
for example in your timer30 timer45 timer60 functions. clear the timerInterval first before setInterval
...
clearInterval(timerInterval);
timerInterval = setInterval(() => { ... }, 1000)
CodePudding user response:
You need to clear intervals one by one, not having only one variable to keep a reference for it.
Added function to clear intervals and resetting them on each button click to make sure they won't overlap.
const FULL_DASH_ARRAY = 283;
const WARNING_THRESHOLD = 10;
const ALERT_THRESHOLD = 5;
const COLOR_CODES = {
info: {
color: "green"
},
warning: {
color: "orange",
threshold: WARNING_THRESHOLD
},
alert: {
color: "red",
threshold: ALERT_THRESHOLD
}
};
var TIME_LIMIT = 0;
let timePassed = 0;
let timeLeft = TIME_LIMIT;
let timerInterval15 = null;
let timerInterval30 = null;
let timerInterval45 = null;
let timerInterval60 = null;
let remainingPathColor = COLOR_CODES.info.color;
document.getElementById("app").innerHTML = `
<div >
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g >
<circle cx="50" cy="50" r="45"></circle>
<path
id="base-timer-path-remaining"
stroke-dasharray="283"
hljs-subst">${remainingPathColor}"
d="
M 50, 50
m -45, 0
a 45,45 0 1,0 90,0
a 45,45 0 1,0 -90,0
"
></path>
</g>
</svg>
<span id="base-timer-label" >${formatTime(
timeLeft
)}</span>
</div>
`;
function clearIntervals(){
clearInterval(timerInterval15);
clearInterval(timerInterval30);
clearInterval(timerInterval45);
clearInterval(timerInterval60);
}
function onTimesUp() {
clearIntervals();
}
function formatTime(time) {
const minutes = Math.floor(time / 60);
let seconds = time % 60;
if (seconds < 10) {
seconds = `0${seconds}`;
}
return `${minutes}:${seconds}`;
}
function setRemainingPathColor(timeLeft) {
const { alert, warning, info } = COLOR_CODES;
if (timeLeft <= alert.threshold) {
document
.getElementById("base-timer-path-remaining")
.classList.remove(warning.color);
document
.getElementById("base-timer-path-remaining")
.classList.add(alert.color);
} else if (timeLeft <= warning.threshold) {
document
.getElementById("base-timer-path-remaining")
.classList.remove(info.color);
document
.getElementById("base-timer-path-remaining")
.classList.add(warning.color);
}
}
function calculateTimeFraction() {
const rawTimeFraction = timeLeft / TIME_LIMIT;
return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
}
function setCircleDasharray() {
const circleDasharray = `${(
calculateTimeFraction() * FULL_DASH_ARRAY
).toFixed(0)} 283`;
document
.getElementById("base-timer-path-remaining")
.setAttribute("stroke-dasharray", circleDasharray);
}
function timer15(){
TIME_LIMIT = 901;
timePassed = 0;
timeLeft = TIME_LIMIT;
clearIntervals();
remainingPathColor = COLOR_CODES.info.color;
timerInterval15 = setInterval(() => {
timePassed = timePassed = 0;
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer30(){
TIME_LIMIT = 1801;
timePassed = 0;
timeLeft = TIME_LIMIT;
clearIntervals();
remainingPathColor = COLOR_CODES.info.color;
timerInterval30 = setInterval(() => {
timePassed = timePassed = 0;
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer45(){
TIME_LIMIT = 2701;
timePassed = 0;
timeLeft = TIME_LIMIT;
clearIntervals();
remainingPathColor = COLOR_CODES.info.color;
timerInterval45 = setInterval(() => {
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
function timer60(){
TIME_LIMIT = 3601;
timePassed = 0;
timeLeft = TIME_LIMIT;
clearIntervals();
remainingPathColor = COLOR_CODES.info.color;
timerInterval60 = setInterval(() => {
timePassed = timePassed = 1;
timeLeft = TIME_LIMIT - timePassed;
document.getElementById("base-timer-label").innerHTML = formatTime(
timeLeft
);
setCircleDasharray();
setRemainingPathColor(timeLeft);
if (timeLeft === 0) {
onTimesUp();
}
}, 1000);
}
body {
font-family: sans-serif;
display: grid;
height: 100vh;
place-items: center;
}
.base-timer {
position: relative;
width: 300px;
height: 300px;
}
.base-timer__svg {
transform: scaleX(-1);
}
.base-timer__circle {
fill: none;
stroke: none;
}
.base-timer__path-elapsed {
stroke-width: 7px;
stroke: grey;
}
.base-timer__path-remaining {
stroke-width: 7px;
stroke-linecap: round;
transform: rotate(90deg);
transform-origin: center;
transition: 1s linear all;
fill-rule: nonzero;
stroke: currentColor;
}
.base-timer__path-remaining.green {
color: rgb(65, 184, 131);
}
.base-timer__path-remaining.orange {
color: orange;
}
.base-timer__path-remaining.red {
color: red;
}
.base-timer__label {
position: absolute;
width: 300px;
height: 300px;
top: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 48px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="timer.css">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<input type="button" onclick="timer15()" value="15 min">
<input type="button" onclick="timer30()" value="30 min">
<input type="button" onclick="timer45()" value="45 min">
<input type="button" onclick="timer60()" value="60 min">
<script src="timer.js"></script>
</body>
</html>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>