Create an accurate millisecond timer that loops in Javascript - javascript

After some research, I understand the most accurate way to create a timer in Javascript is to compare the elapsed time from a starting point using date.now() -as this answer suggests.
var startTime = Date.now();
var interval = setInterval(function() {
var elapsedTime = Date.now() - startTime;
var time = (elapsedTime / 1000).toFixed(3);
console.log(time);
}, 10);
This provides the accuracy I am looking for, but I am looking to make this timer reset itself after a certain value (let's say var total = 12000). This value is determined by the length of a video playlist (I am building a 'live' playhead for a video program) and is a variable.
I'm stuck how to go about this, as the counter is counting elapsed time from a certain point in time, it doesn't quite fit the logic of what I am looking for. Any suggestions would be appreciated.

You could use a .setTimeout() at the end of your code to restart your .setInterval(), after the desired time has passed
function runInterval (loopAfter) {
var startTime = Date.now();
var interval = setInterval(function() {
var elapsedTime = Date.now() - startTime;
var time = (elapsedTime / 1000).toFixed(3);
console.log(time);
}, 10);
setTimeout(() => {
clearInterval(interval);
runInterval(loopAfter);
}, loopAfter);
}
runInterval(5000);

Try this:
var startTime = Date.now();
let total = 0;
var interval = setInterval(function() {
if (total === 12000) {
total = 0;
startTime = Date.now();
} else {
total++;
var elapsedTime = Date.now() - startTime;
var time = (elapsedTime / 1000).toFixed(3);
}
console.log(time);
}, 10);

Related

While loops conditions and setInterval()

I want to preface this by saying I have very little knowledge of JS as you'll probably be able to tell, I also wasn't sure what to title this.
Anyway, I'm trying to make a simple script where it counts up to 30 minutes and then at 30 minutes returns a message by using a while loop. However, I want the condition where heliTime =! endTime to only run every minute. I can get the script to run every minute however in runs the entire function each minute instead of just one check.
setInterval(function arran() {
var startTime = 0;
var minutes = 1000 * 60;
//var seconds = 1000;
var heliTime = startTime
var endTime = 30 * minutes;
var messageCount = 0;
while (heliTime !== endTime) {
var messageCount = messageCount + 1;
console.log("No heli yet! " + messageCount);
var heliTime = heliTime + minutes;
}
return console.log("Heli should be arriving soon!");
},60 * 1000);
The messageCount variable is just debug so that can be ignored, any help with my problem would be greatly appreciated. :)
I would say that measuring real time by the frequence of callbacks by setInterval as Tobbe Widner suggest seems to me as a strange idea. I think it is better to use some explicit time source such as
function runDelayedWithProgress(waitIntervalSeconds, delayedAction, progressIntervalSeconds, progressAction) {
var startTime = new Date().getTime();
var iid = setInterval(function() {
var curTime = new Date().getTime()
var elapsedSeconds = (curTime - startTime)/1000;
if(elapsedSeconds >= waitIntervalSeconds) {
clearInterval(iid);
delayedAction();
}
else {
progressAction(Math.round(elapsedSeconds));
}
}, progressIntervalSeconds*1000);
}
runDelayedWithProgress(30*60, function() {
console.log("Heli should be arriving soon!")
},
60, function(elapsed){
console.log("No heli yet! " + elapsed);
});

Understanding an update function. Elapsed time minus itself

Im trying to wrap my head around this function. Mainly the NewTime=time-lastTime; line. Why is it needed? What exactly does it do? From what I gather ir takes the elapsed start time which increments starting at zero. Then takes away the last time we saw which will always leave me with the difference of the two times. But how does it use this to update?
let Count = 0;
let interval = 500;
let lastTime = 0;
function update(time = 0) {
const NewTime = time - lastTime;
lastTime = time;
Count += NewTime;
if (Count > interval) {
player.pos.y++;
Count = 0;
}
draw();
requestAnimationFrame(update);
}

Javascript .getTime() inconsistent results between between windows

I need to show a countdown timer. I get time from my server and should count down to zero, based on the following:
var now = new Date().getTime();
var timeRemaining = endTime - now;
.... I start the contdown timer with timeRemining
What happens is when I start the timer in two different tabs, the timer is off by about 2 seconds.
If I do this in one tab and another private window/tab, the timer can be different much much more.
Is there something I can do about this?
var end = new Date('2015-10-27T13:00:00');
var endTime = end.getTime();
var div = document.getElementById('time');
setInterval(function() {
var now = new Date().getTime();
var timeRemaining = endTime - now;
var seconds = timeRemaining / 1000;
div.innerText = Math.floor(seconds);
}, 1000);
<div id="time"></div>

Accurate Javascript Timer

I am trying to build an accurate countdown timer that shows mins and seconds left. I have tried 2 approaches. Approach 1 uses the setTimer function and calculates the drift. For that approach, some values get skipped and some values get repeated. Approach 2 yields all of the necessary values, but the values are not getting printed to the screen at even intervals (tested in repl.it). How can I make a timer that is both accurate and prints all of the values ?
Approach1:
function countTime(duration) {
var expected = 1;
var secsLeft;
var startT = new Date().getTime();
var oneSecond = 1000;
var expected = startT + oneSecond;
window.setTimeout(step, oneSecond);
function step() {
var nowT = new Date().getTime();
var drift = nowT - expected;
if (drift > oneSecond) {
console.log("drift is over 1 second long!");
}
console.log('drift is ' + drift);
var msDelta = nowT - startT;
var secsLeft = duration - Math.floor(msDelta / 1000);
console.log("secsLeft" + secsLeft);
if (secsLeft === 0) {
++count;
console.log("cleared");
} else {
expected += oneSecond;
setTimeout(step, Math.max(0, oneSecond - drift));
}
}
}
countTime(60);
Approach2:
function countTime(duration) {
var expected = 1;
var secsLeft;
var inter;
var startT = new Date().getTime();
inter = setInterval(function() {
//change in seconds
var sChange = Math.floor((new Date().getTime() - startT) / 1000);
if (sChange === expected) {
expected++;
secsLeft = duration - sChange;
console.log("seconds Left" + secsLeft);
}
if (secsLeft === 0) {
window.clearInterval(inter);
console.log("cleared");
}
}, 100);
}
countTime(60);
Consider using requestAnimationFrame.
function countTime(duration) {
requestAnimationFrame(function(starttime) {
var last = null;
function frame(delta) {
var timeleft = Math.floor(duration - (delta - starttime)/1000),
minutes = Math.floor(timeleft/60),
seconds = timeleft%60;
if( timeleft > 0) {
if( last != timeleft) {
console.log("Time left: "+minutes+"m "+seconds+"s");
last = timeleft;
}
requestAnimationFrame(frame);
}
}
frame(starttime);
});
}
countTime(60);
This will be precise to within the framerate of the browser itself :)
function(){
date = get the date
curSeconds = compute the number of seconds to be displayed
if(oldSeconds!=curSeconds) then refresh display and do oldSeconds = curSeconds;
}
Call this function quite often, the more you call it, the more accurate your timer will be. I advise you to use requestAnimationFrame() instead of setTimout() it will be called 60 times per second (period 16ms) since it is the refresh rate of most displays, it is the maximum visible "accuracy". Also it won't be called when page is not visible.
Simple, clean, no drift over long periods of time.
It also handle not being called for a while.

Keep track of how much time is spent showing certain elements on the page

So lets say we have 4 Divs (3 hidden, 1 visible), the user is able to toggle between them through javascript/jQuery.
I want to calculate time spent on each Div, and send an xhr containing that time to server to store it in the database. This xhr will be sent when the user toggle the div view.
How can I do that? Any hints will be greatly appreciated.
Thanks,
At any point, you can record a a start/lap time in a variable with:
var start = new Date();
When you want to calculate the elapsed time, simply subtract the stored date from a new Date instance:
var elapsed = new Date() - start;
This will give you the elapsed time in milliseconds. Do additional math (division) to calculate seconds, minutes, etc.
Here you go:
HTML:
<div id="divs">
<div>First</div>
<div class="selected">Second</div>
<div>Third</div>
<div>Fourth</div>
</div>
<p id="output"></p>
JavaScript:
var divs = $('#divs > div'),
output = $('#output'),
tarr = [0, 0, 0, 0],
delay = 100;
divs.click(function() {
$(this).addClass('selected').siblings().removeClass('selected');
});
setInterval(function() {
var idx = divs.filter('.selected').index();
tarr[idx] = tarr[idx] + delay;
output.text('Times (in ms): ' + tarr);
}, delay);
Live demo: http://jsfiddle.net/7svZr/2/
I keep the times in milliseconds because integers are cleaner and safer (0.1 + 0.2 != 0.3). Note that you can adjust the "precision" (the delay of the interval function) by setting the delay variable.
Here is a reusable class, example is included in code:
/*
Help track time lapse - tells you the time difference between each "check()" and since the "start()"
*/
var TimeCapture = function () {
var start = new Date().getTime();
var last = start;
var now = start;
this.start = function () {
start = new Date().getTime();
};
this.check = function (message) {
now = (new Date().getTime());
console.log(message, 'START:', now - start, 'LAST:', now - last);
last = now;
};
};
//Example:
var time = new TimeCapture();
//begin tracking time
time.start();
//...do stuff
time.check('say something here')//look at your console for output
//..do more stuff
time.check('say something else')//look at your console for output
//..do more stuff
time.check('say something else one more time')//look at your console for output
I use a really easy function to provide time elapsed in this format: hh/mm/ss
onclick/onfocus/etc..
var start_time = new Date();
on leaving:
var end_time = new Date();
var elapsed_ms = end_time - start_time;
var seconds = Math.round(elapsed_ms / 1000);
var minutes = Math.round(seconds / 60);
var hours = Math.round(minutes / 60);
var sec = TrimSecondsMinutes(seconds);
var min = TrimSecondsMinutes(minutes);
function TrimSecondsMinutes(elapsed) {
if (elapsed >= 60)
return TrimSecondsMinutes(elapsed - 60);
return elapsed;
}
Javascript console internally has a function called "console.time() and console.timeEnd() to do the same. Simple you can use them
console.time("List API");
setTimeout(()=> {
console.timeEnd("List API");
},5000);
More details can be found here
https://developer.mozilla.org/en-US/docs/Web/API/Console/time
I created an ES6 class based on #Shawn Dotey's answer.
The check() method does not log a message, but returns the elapsed time.
The method start() is not needed in his example (the constructor already "starts" it). So I replaced it by reset() which makes more sense.
export default class TimeCapture
{
constructor()
{
this.reset();
}
reset()
{
this.startTime = new Date().getTime();
this.lastTime = this.startTime;
this.nowTime = this.startTime;
}
check()
{
this.nowTime = new Date().getTime();
const elapsed = this.nowTime - this.lastTime;
this.lastTime = this.nowTime;
return elapsed;
}
}
Use it in your project like this:
import TimeCapture from './time-capture';
const timeCapture = new TimeCapture();
setTimeout(function() {
console.log( timeCapture.check() + " ms have elapsed" ); //~100 ms have elapsed
timeCapture.reset();
setTimeout(function() {
console.log( timeCapture.check() + " ms have elapsed" ); //~200 ms have elapsed
}, 200);
}, 100);

Categories