clearInterval is not clearing setInterval - javascript

I have made a memory game with a timer that start at 10 minutes and counts down every second to 0. This function is only called once and has the following setInterval function:
game.countdown = setInterval(function() {
if(game.timeLeft <= 0){
gameEnded = true;
}
if(!gameEnded){
// lower one second
game.timeLeft--;
var timespan = document.querySelector('.timeleft');
var minutes = pad(Math.floor((game.timeLeft / 60)),2 );
var newSeconds = pad(Math.floor(game.timeLeft - (minutes * 60)),2 );
function pad(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
var niceTime = minutes + ":" + newSeconds;
timespan.innerHTML = niceTime;
// Then alter time bar on .innertimer
// Calculate percentage starting at 0%
var percentageDone = (Math.floor((10*60 - game.timeLeft) / (10*60) * 10000) / 100);
$(".timer").css({"background": "-webkit-linear-gradient(left, white " + percentageDone + "%, green " + percentageDone + "%)"});
}
}, 1000);
I store the setInterval in object game under variable name countdown. When the game is ended I call another function that has the clearInterval:
clearInterval(game.countdown);
Then when it goes to the next level it calls the setInterval function again and stores it again in game.countdown. But now for every second it takes 2 seconds. The next level 3 seconds. You can see there are multiple setInterval's at work because it's not done at the same time.
Hope someone can really help me out debugging this problem.

What I've done to work around the issue is the following. The interval is only being called if the following is true:
if (undefined == game.countdown){
This way if there is a countdown defined it's calling it again. And since I'm storing the game.timeLeft not in the function itself I can just refill game.timeLeft.

Related

Countdown based on timezone with jQuery

I worked with this:
(function() {
var timeElement, eventTime, currentTime, duration, interval, intervalId;
interval = 1000; // 1 second
// get time element
timeElement = document.querySelector("#countdown");
// calculate difference between two times
eventTime = moment.tz("2022-05-29T08:00:00", "Europe/Berlin");
// based on time set in user's computer time / OS
currentTime = moment.tz();
// get duration between two times
duration = moment.duration(eventTime.diff(currentTime));
// loop to countdown every 1 second
setInterval(function() {
// get updated duration
duration = moment.duration(duration - interval, 'milliseconds');
// if duration is >= 0
if (duration.asSeconds() <= 0) {
clearInterval(intervalId);
// hide the countdown element
timeElement.classList.add("hidden");
} else {
// otherwise, show the updated countdown
timeElement.innerText = duration.days() + ":" + duration.hours() + ":" + duration.minutes() + ":" + duration.seconds();
}
}, interval);
}());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment-with-locales.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.17/moment-timezone-with-data-2012-2022.min.js"></script>
<div id="countdown"></div>
Unfortunately, the time doesn't get calculated correctly. If you change for example 2022-05-29 to 2022-08-29, nothing changes. Additionally, every value should have two digits.
Has someone an idea to fix that? Would be very thankful!
Your question about momentjs is answered here; use asDays() not days()
You can pad a string with 0's using the function padStart(length, withWhat) Mozilla Developer Network Documentation
//...snip...
} else {
// otherwise, show the updated countdown
timeElement.innerText =
duration.asDays().toFixed().padStart(2, 0) + ":" +
duration.hours().toString().padStart(2, 0) + ":" +
duration.minutes().toString().padStart(2, 0) + ":" +
duration.seconds().toString().padStart(2, 0);
}
//...snip...

Multi countdown

I have a web page where I entered a countdown code and it works well. However, I can only call it 1 time with the id in html.
Second or third time, it no longer works. How can I always use it? I would need it 3 or 4 times on the page. Thank you.
This is the code:
var counter = null;
window.onload = function() {
initCounter();
};
function initCounter() {
// get count from localStorage, or set to initial value of 1000
count = getLocalStorage('count') || 1000;
counter = setInterval(timer, 1000); //1000 will run it every 1 second
}
function setLocalStorage(key, val) {
if (window.localStorage) {
window.localStorage.setItem(key, val);
}
return val;
}
function getLocalStorage(key) {
return window.localStorage ? window.localStorage.getItem(key) : '';
}
function timer() {
count = setLocalStorage('count', count - 1);
if (count == -1) {
clearInterval(counter);
return;
}
var seconds = count % 60;
var minutes = Math.floor(count / 60);
var hours = Math.floor(minutes / 60);
minutes %= 60;
hours %= 60;
document.getElementById("timer").innerHTML = hours + " ore " + minutes + " min " + seconds + " sec"; // watch for spelling
}
You need to encapsulate the functionality in a way that can be called many times. It usually helps to think about the question "As a programmer, how I'd like to use this?"
Usually, it's a single function that takes some parameters and does something and/or returns something.
As an example... wouldn't it be nice if we had a function startMyTimer(...) that takes a timerId, and an element and sets up a timer that will update that element? We already have the signature:
function startMyTimer(timerId, element) { ... }
And now you can build everything inside this function. JS allows declaring functions within functions, which helps with encapsulation, so copying from your code it would look like:
function startMyTimer(timerId, element) {
var count = getLocalStorage(timerId) || 1000;
var counter = setInterval(timer, 1000); //1000 will run it every 1 second
function timer() {
count = setLocalStorage(timerId, count - 1);
if (count == -1) {
clearInterval(counter);
return;
}
var seconds = count % 60;
var minutes = Math.floor(count / 60);
var hours = Math.floor(minutes / 60);
minutes %= 60;
hours %= 60;
element.innerHTML = hours + " ore " + minutes + " min " + seconds + " sec"; // watch for spelling
}
}
Note that now count and counter are both private to the scope of startMyTimer, so only within this function (and any function inside this one, such as function timer()) will see these variables.
So if you want to do exactly what you did, you'd use this function as
window.onload = function() {
startMyTimer('count', document.getElementById("timer"));
};
Again, this is just an example of a posible solution - Maybe you could pass in the element id instead of the element, or a timer duration, etc., and the best solution is the one that fits best your needs.

Reset Timer every x minutes/hour

I am trying two create to separate timers. One timer counts down to a date and displays a countdown and the other counts down on an interval and resets (ie: 5 hours and resets).
The one I am having trouble with is the second option. I am trying to create a countdown that is relative to real-time and then resets once it reaches zero. So for example setting it to 2 days and 5 hours. Once this completes the clock resets to 2 days 5 hours. I am having trouble getting the clock to reset at the specified time and loop without having negative numbers. I tried this two separate ways but feel like I am over-complicating things.
The reason I use real-time is so that the clock will be the same if you open it in another tab. If I create a regular timer it will reset upon refreshing the page.
codpen
In this example I tried to reset the counter every 40 seconds but couldn't get it to work. Ultimately I want to be able to specify the date with ie: 00:12:00 (12 hours countdown) and then have it reset automatically. I just can't figure out how to maintain the counting without going to negative numbers or freezing it.
function timer() {
var currentTime = new Date()
var date = currentTime.getDate()
var hours = currentTime.getHours()
var minutes = currentTime.getMinutes()
var seconds = currentTime.getSeconds()
var daysLeft = 0;
var hoursLeft = 24 - hours;
var minsLeft = 60 - minutes;
var secsLeft = 60 - seconds;
// counter freezes at 40 seconds and hangs for 20seconds
if(secsLeft => 40) {
secsLeft = 40 - seconds
if(secsLeft < 0) {
secsLeft = 40
}
}
document.getElementById('timerUpFront').innerHTML= "<br><br><strong>Duration Countdown with Infinite Reset #2</strong><br>" + daysLeft + " days " + hoursLeft + " hours " + minsLeft + " minutes " + secsLeft + " seconds";
}
var countdownTimer = setInterval('timer()', 1000);
codpen
you can separate the timer to functions to simplify it and apply the following logic
function startTimer () {
val targetRemainedSeconds = // calculate the value
val remainedSeconds = targetRemainedSeconds
setInterval(timer(), 1000)
}
function timer () {
remainedSeconds--
if (remainedSeconds < 0) reaminedSeconds = targetReaminedSeconds // reset the timer
timerUpdate()
}
function timerUpdate() {
// use 'remainedSeconds' to update timer
}

Making a min:sec counter using javascript

I am trying to make a small question/answer quiz game using react, and I want to show a timer that counts down every second. Each game will last 10, 15, or 30 minutes at most, so I want to show a timer that updates every second in the bottom of the screen (in big font, of course!), something like 15:00, 14:59, 14:58, and so on until it hits 00:00.
So, given a start time such as 2016-04-25T08:00:00Z, and an end time after adding 15 min of 2016-04-25T08:15:00Z, I want to start the countdown.
My issue is that I am not understanding how to use setIntervals to keep calling my method to find the remaining time.
timeLeft = Math.round(timeLeft/1000) * 1000;
const timer = new Date(timeLeft);
return timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
EDIT: You've edited your question. You will need the time padding, and the method below will be faster than what you are using, but to answer your question about setInterval:
First, define your function to run your timer and decrement each time it's called:
var timeLeft; // this is the time left
var elem; // DOM element where your timer text goes
var interval = null; // the interval pointer will be stored in this variable
function tick() {
timeLeft = Math.round(timeLeft / 1000) * 1000;
const timer = new Date(timeLeft);
var time = timer.getUTCMinutes() + ':' + timer.getUTCSeconds();
elem.innerHTML = time;
timeLeft -= 1000; // decrement one second
if (timeLeft < 0) {
clearInterval(interval);
}
}
interval = setInterval(tick, 1000);
OG Answer:
No, I do not believe there is a built-in way to display time differences.
Let's say you have two date objects:
var start = Date.now();
var end = Date.now() + 15 * 60 * 1000; // 15 minutes
Then you can subtract the two Date objects to get a number of milliseconds between them:
var diff = (end - start) / 1000; // difference in seconds
To get the number of minutes, you take diff and divide it by 60 and floor that result:
var minutes = Math.floor(diff / 60);
To get the number of seconds, you take the modulus to get the remainder after the minutes are removed:
var seconds = diff % 60;
But you want these two padded by zeros, so to do that, you convert to Strings and check if they are two characters long. If not, you prepend a zero:
// assumes num is a whole number
function pad2Digits(num) {
var str = num.toString();
if (str.length === 1) {
str = '0' + str;
}
return str;
}
var time = pad2Digits(minutes) + ':' + pad2Digits(seconds);
Now you have the time in minutes and seconds.

Timer control in javascript

I am using timer in my project , I am having two problems in it. When start button is press time should start & when end button is press time should end.
But 1)when end button is clicked
time is not stopping .
2)when time decrease & reach 1 minute..time is stopped ..it should reduse in seconds also
var tim;
var min = 10;
var sec = 10;
var f = new Date();
function f1() {
f2();
document.getElementById("starttime").innerHTML = "Your started your Exam at " + f.getHours() + ":" + f.getMinutes();
}
function f2() {
if (parseInt(sec) > 0) {
sec = parseInt(sec) - 1;
document.getElementById("showtime").innerHTML = "Your Left Time is :" + min + " Minutes ," + sec + " Seconds";
tim = setTimeout("f2()", 1000);
} else {
if (parseInt(sec) == 0) {
min = parseInt(min) - 1;
if (parseInt(min) == 0) {
clearTimeout(tim);
location.href = ".././Home/Login";
} else {
sec = 60;
document.getElementById("showtime").innerHTML = "Your Left Time is :" + min + " Minutes ," + sec + " Seconds";
tim = setTimeout("f2()", 1000);
}
}
}
}
My suggestion would be this:
Fiddle
var tim;
var sec;
var f = new Date();
function f1() {
sec = 10 * 60;
f2();
document.getElementById("starttime").innerHTML = "Your started your Exam at " + f.getHours() + ":" + f.getMinutes();
}
function f2() {
if (sec > 0) {
sec--;
tim = setTimeout(f2, 1000);
} else {
document.getElementById("starttime").innerHTML = "times up!!!!";
}
var min = Math.floor(sec / 60);
var secDisplay = sec % 60;
document.getElementById("showtime").innerHTML = "Your Left Time is : " + min + " Minutes," + secDisplay + " Seconds";
}
function end() {
clearTimeout(tim);
sec = 0;
f2();
}
Changes are:
Removed the min variable and only use the total seconds instead of two variables. We can easily calculate the minutes based on the total seconds, for the display purposes. Using the seconds variable makes it much easier to check the time remaining. As you can see the code is simplified a lot.
Changed the setTimeout to take the function as an argument, not a string.
Added end() function, to be called when the end button is clicked.
Moved the seconds count to inside f1() so that it can be started and ended repeatedly without reloading the page.
Removed unnecessary parseInt() calls. The sec variable is already of numerical type so no need to convert it.
The timer will stop when the seconds reduce to 0. If you want it to stop when the time remaining reaches one minute, just change the condition in f2() to if (sec > 60) {
For your first question about the end button i cannot see any end button functionality. but you could have a stop function that clears the timeout.
function f3() {
clearTimeout(tim);
//update any text you wish here or move to the next page..
}
For your second question why it ends at 1 minute. You are decreasing the minute value before you check if it is zero. So when you come to f2, sec is 0 and min is 1 you then decrease min to 0.. And then check if it is zero and end the execution.
To solve that move your "min = parseInt(min) - 1;" to after the else and it should count the last minute too.
PS. you don't need parseint since you are using numbers allready

Categories