I am creating an application that uses a timer to draw lines to several canvases while updating stats to DIVs. In order to create the smoothest animation possible I've had to set the setInterval() timer to the smallest delay possible, which from my understanding, is between 10-15 milliseconds across browsers.
The issue I am having is with the stopwatch that tracks the scenarios running time. The stopwatch itself works well enough as I have established using console.log, however, the setInterval() timer slows down when I try to update the DOM element. This has lead me to believe that in combination with the small timer tick delay there is a performance issue with the way I am updating the DOM element.
Code:
function draw() {
var drawTimer = setInterval(drawStuffTest, 15);
var timer = doc.getElementById('time');
var milliseconds = 0;
var seconds = 0;
var minutes = 0;
function updateTimer() {
//clear the old elapsed time
timer.innerHTML = "";
milliseconds += 15;
//increment seconds
if (milliseconds >= 1000) {
seconds++;
milliseconds = 0;
}
//increment minutes
if(seconds >= 60)
{
seconds = 0;
minutes++;
}
//Pad minutes and seconds with leading zeroes if either is lest than 10
var secondsString = ( seconds < 10 ? "0" : "" ) + seconds;
var minutesString = ( minutes < 10 ? "0" : "" ) + minutes;
var elapsedTime = minutesString + ":" + secondsString;
/* The timer works fine when I just use console.log to display the
timer however once I add the following statement to update the DOM
element the timer slows down */
//timer.innerHTML = elapsedTime;
console.log(elapsedTime);
}
Does anyone have any suggestions?
Related
I use countTime function for incrementing timer, I have 1 function gameStart to initialize game structures and assign variable totalSecond = 0 and variable timeStart = setInterval(countTime, 1000). I have a button that when clicked it will run the function gameStart. When I run the code for the first time, everything is fine, but when I press the button many times with the newGame event, it increases the time very quickly. I have to clearInteval when I lose the game so time can stop. Thank for help me
function countTimer() {
totalSeconds++;
var hour = Math.floor(totalSeconds /3600);
var minute = Math.floor((totalSeconds - hour*3600)/60);
var seconds = totalSeconds - (hour*3600 + minute*60);
if(hour < 10)
hour = "0"+hour;
if(minute < 10)
minute = "0"+minute;
if(seconds < 10)
seconds = "0"+seconds;
document.getElementById("countUp").innerHTML = hour + ":" + minute + ":" + seconds;
}
function gameStart() {
timerVar = setInterval(countTimer, 1000);
totalSeconds = 0;
rows = parseInt(document.getElementById("rows").value);
cols = parseInt(document.getElementById("cols").value);
mineCount = parseInt(document.getElementById("mines").value);
rows = rows > 10 ? rows : 10;
cols = cols > 10 ? cols : 10;
mCount = mCount > 10 ? mCount : 10;
openedCells=0;
initBoard();
initHTML();
}
setInterval functions never expire until you call clearInterval. In your case, every time you run gameStart, a new interval is created that counts up.
You are left with multiple intervals, making the timer go up quicker and quicker.
A quick fix would be to declare timerVar outside the Function, then clear and re-make it every time gameStart is called.
timerVar = setInterval(()=>{},1000) // Empty interval
function gameStart() {
clearInterval(timerVar)
timerVar = setInterval(countTimer, 1000);
totalSeconds = 0;
I'm unable to test this at the moment, but it should work.
function initTimer(timeLeft) {
var Me = this,
TotalSeconds = 35,
Seconds = Math.floor(timeLeft);
var x = window.setInterval(function() {
var timer = Seconds;
if(timer === -1) { clearInterval(x); return; }
$('#div').html('00:' + (timer < 10 ? '0' + timer : timer));
Seconds--;
},1000);
}
I have this code. Everything works fine, when this tab is active in browser, but when I change tab and return in tab later it has problems. To be more precise, it Incorrectly displays the time.
I'd also tried setTimeout, but problem was the same.
One idea, which I have is: HTML5 Web Workers...
But here is another problem... browsers support.
can someone help to solve this problem?
How can I write setInterval, which works properly,even when tab is not active
Use the Date object to calculate time. Don't rely on a timer firing when you ask it to (they are NOT real-time) because your only guarantee is that it'll not fire before you ask it to. It could fire much later, especially for an inactive tab. Try something like this:
function initTimer(periodInSeconds) {
var end = Date.now() + periodInSeconds * 1000;
var x = window.setInterval(function() {
var timeLeft = Math.floor((end - Date.now()) / 1000);
if(timeLeft < 0) { clearInterval(x); return; }
$('#div').html('00:' + (timeLeft < 10 ? '0' + timeLeft : timeLeft));
},200);
}
initTimer(10);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div"></div>
Note that by checking it more frequently we can make sure it's never off by too much.
JavaScript timers are not reliable, even when the tab is active. They only guarantee that at least as much time as you specified has passed; there is no guarantee that exactly that amount of time, or even anything close to it, has passed.
To solve this, whenever the interval fires, note what time it is. You really only need to keep track of two times: the current time, and the time that the previous interval fired. By subtracting the previous tick's time from the current tick's time, you can know how much time has actually passed between the two, and run your calculations accordingly.
Here's a basic outline of how something like this might look:
function initTimer(timeLeft) {
var Me = this,
TotalSeconds = 35,
Seconds = Math.floor(timeLeft),
CurrentTime = Date.now(),
PreviousTime = null;
var x = window.setInterval(function() {
var timer = Seconds,
timePassed;
PreviousTime = CurrentTime;
CurrentTime = Date.now();
timePassed = CurrentTime - PreviousTime;
if(timer < 0) { clearInterval(x); return; }
$('#div').html('00:' + (timer < 10 ? '0' + timer : timer));
Seconds = Seconds - timePassed;
},1000);
}
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
}
I created a countdown timer in Javascript; it was successful, expect not complete. In fact, mathematically, it is correct, but Google Chrome's browser settings "pause" (for lack of a better term) SetInterval/Timeout, which means that if a user of my countdown program switches between tabs on their browser, then the execution of the function will not occur exactly at the set time limit.
I need help implementing this basic time logic from W3Schools:
http://www.w3schools.com/js/tryit.asp?filename=tryjs_timing_clock
<!DOCTYPE html>
<html>
<head>
<script>
function startTime() {
var today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
m = checkTime(m);
s = checkTime(s);
document.getElementById('txt').innerHTML =
h + ":" + m + ":" + s;
var t = setTimeout(startTime, 500);
}
function checkTime(i) {
if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10
return i;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>
and this attempt to account for the browser SetInterval/Timeout interference: http://jsfiddle.net/7f6DX/31/
var div = $('div');
var a = 0;
var delay = (1000 / 30);
var now, before = new Date();
setInterval(function() {
now = new Date();
var elapsedTime = (now.getTime() - before.getTime());
if(elapsedTime > delay)
//Recover the motion lost while inactive.
a += Math.floor(elapsedTime/delay);
else
a++;
div.css("right", a);
before = new Date();
}, delay);
Thanks for any help that you can provide.
You should use real-world time to update your timer instead of relying on the accuracy of setInterval.
The w3schools example you gave does exactly this; every 500ms it grabs the current time, formats it, and updates the display. When the tab is inactive, this update may occur less frequently than 500ms (Chrome can slow it down to once every 1-2s), but nevertheless, when the update does occur, you will display correct information.
// countdown for 1 minute
countdown(60);
function countdown(seconds) {
// current timestamp.
var now = new Date().getTime();
// target timestamp; we will compute the remaining time
// relative to this date.
var target = new Date(now + seconds * 1000);
// update frequency; note, this is flexible, and when the tab is
// inactive, there are no guarantees that the countdown will update
// at this frequency.
var update = 500;
var int = setInterval(function () {
// current timestamp
var now = new Date();
// remaining time, in seconds
var remaining = (target - now) / 1000;
// if done, alert
if (remaining < 0) {
clearInterval(int);
return;
}
// format
var minutes = ~~(remaining / 60);
var seconds = ~~(remaining % 60);
// display
document.getElementById("countdown").innerHTML
= format(minutes) + ":" + format(seconds);
}, update);
}
function format(num) {
return num < 10 ? "0" + num : num;
}
<div id="countdown"></div>
Run this snippet and switch around to different tabs. Your countdown will be off by a maximum of 500ms (the update frequency).
For what it's worth, a similar idea can be applied to animations.
When designing an animation, you should have a formula for the position x as a function of time t. Your rendering clock (whether it is setInterval, setTimeout, or requestAnimationFrame) is not necessarily reliable, but your physics clock (real-world time) is. You should decouple the two.
Every time you need to render a frame, consult the physics clock for the time t, calculate the position x, and render that position. This is a really great blog post which goes into great detail on animations and physics, from which I borrowed the above idea.
I am trying to build multiple timers for my web page, so far I have,
$('.timer').each(function() {
var timer = setInterval(function() {
var time = $(this).text().split(':');
var minutes = parseInt(time[0], 10);
var seconds = parseInt(time[1], 10);
// TIMER RUN OUT
if (!minutes && !seconds) {
// CLEAR TIMER
clearInterval(timer);
// MINUS SECONDS
} else {
seconds -= 1;
}
// MINUS MINUTES
if (seconds < 0 && minutes != 0) {
minutes -= 1;
seconds = 59;
// ADD ZERO IF SECONDS LESS THAN 10
} else {
if (seconds < 10) {
seconds = '0' + seconds;
}
}
// ADD ZERO IF MINUTES LESS THAN 10
if (minutes < 10) {
minutes = '0' + minutes;
}
}, 1000);
});
This doesn't work though! Where am I going wrong!
Thanks
First, inside your setInterval callback, this no longer refers to the .timer element. Try changing that to self and add var self = this; before the call to setInterval. Second, you never write your time back to your .timer element.
Are you trying to display a clock counting down? In that case, you're not updating the text after all the calculations. Try adding:
$(this).text(minutes+':'+seconds);