Jquery stopwatch with milliseconds (accurate) - javascript

I'm trying to create a stopwatch with miliseconds which is as accurate as possible.
Of course the browser/server/cpu or whatever will need more than 1 ms to execute the function and display the digit on the watch. So I thought i want to reset the ms to 0 each time a second goes up.
jQuery code looks like this.
(function($) {
$.fn.stopwatch = function() {
// The Element where the HTML code is added
var clock = $(this);
var timestamprunningms;
var timestampstartms;
var milliseconds = 0;
// Predefinition of the timestamprunningseconds variable
var timestamprunningseconds;
var display = clock.find("#display");
var time = clock.find("#time");
// Predefinition of the seconds variable
// Value 0 because it is used to define
// The timestampstartseconds variable in the click-event
var seconds = 0;
// Predefinition for the timestampstartseconds variable
var timestampstartseconds;
// Predefinition for the timer variable
var timer;
// Time Variables
var h = clock.find("#h");
var m = clock.find("#m");
var s = clock.find("#s");
var ms = clock.find("#ms");
// Button Variables
var resetlog = clock.find("#resetlog")
var showms = clock.find("#showms")
var hidems = clock.find("#hidems")
var start = clock.find("#start");
var pause = clock.find("#pause");
var reset = clock.find("#reset");
var log = clock.find("#log");
ms.hide();
resetlog.click(function (){
time.html("");
});
// Hides the pause and hidems Button
pause.hide();
hidems.hide();
// Triggered by clicking the start button
start.click(function() {
// Hides the start and shows the pause button
start.hide(),
pause.show(),
// Defines the value of timestampstartseconds or saves it
// if there is a value in seconds
timestampstartseconds = Math.round(new Date().getTime() / 1000) - seconds;
timestampstartms = new Date().getTime() - milliseconds;
timer = setInterval(do_time, 20);
});
// Triggered by clicking the pause button
pause.click(function() {
// Resets the interval in which the do_time function occurs
clearInterval(timer),
// Hides the pause and shows the start button
pause.hide(),
start.show(),
timer = 0;
});
// Triggered by clicking the reset button
reset.click(function() {
// Resets the interval in which the do_time function occurs
clearInterval(timer),
// Resets the value of the display
h.html("00"),
m.html("00"),
s.html("00"),
ms.html("000")
// Hides the pause and shows the start button
pause.hide(),
start.show();
seconds = 0;
});
log.click(function() {
time.append("<li>" + display.text() + "</li>");
});
// The function for calculating the seconds/minutes/hours
showms.click(function() {
showms.hide();
hidems.show();
ms.show();
});
hidems.click(function() {
hidems.hide();
showms.show();
ms.hide();
});
function do_time() {
// Timestamp that refreshes everytime the function is executed
timestamprunningseconds = Math.round(new Date().getTime() / 1000);
timestamprunningms = new Date().getTime();
// The actual seconds that are going to be displayed
milliseconds = timestamprunningms - timestampstartms;
seconds = timestamprunningseconds - timestampstartseconds;
// Value of the display
var hour = parseFloat(h.text());
var minute = parseFloat(m.text());
if (milliseconds > 999) {
milliseconds = 0;
timestampstartms = new Date().getTime();
}
// Reset seconds display and add a minute every time 60 seconds pass
if (seconds > 59) {
seconds = 0;
timestampstartseconds = Math.round(new Date().getTime() / 1000);
minute++;
}
// Reset minute display and add an hour every time 60 minutes pass
if (minute > 59) {
minute = 0;
hour++;
}
// Display value
h.html("0".substring(hour >= 10) + hour);
m.html("0".substring(minute >= 10) + minute);
s.html("0".substring(seconds >= 10) + seconds.toString());
ms.html(":" + "0".substring(milliseconds >= 100) +"0".substring(milliseconds >= 10) + milliseconds.toString());
};
};
})(jQuery);
As I already said, my goal is to reset the millisecond timer every time a second goes up. (the seconds are accurate, the milliseconds aren't).
would that be something like this?:
while (seconds++) {
milliseconds = 0;
timestampstartms = new Date().getTime();
}
I'm really new to javascript/jQuery and programming in general so it would be very nice if you could help me with this problem and maybe give a little feedback so I can improve.

Ok I found a solution: i just added a variable which is like a timestamp of the current second. It has a default value of 0 and goes 1 up if the seconds that is used in the display is greater than the second timestamp.
looks a bit like this: var secondnow = 0; (on top of the jQuery function)
and this is how it's used
if (seconds > secondnow) {
milliseconds = 0;
secondnow++;
timestampstartms = new Date().getTime();
console.log(secondnow);
}
(in the function do_time)

Related

Create a countdown timer (that accounts for SetInterval/Timeout Google Chrome tab "error")

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.

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.

from last minute of an hour to first minute of next hour

I have built a page that store a message and a user to send the message to in a db. The form has a restriction: you can't use the same user for the next 30 seconds from when you have posted the message to the db.
function undisable (id,time){
setTimeout(function() {
$('#'+id).prop('disabled', false);
}, (30000-time));
}
$('#destinatario option').each(function(){
var ds = $(this).attr('data-ts');
var dateArray = ds.split(" "); // split the date and time
var ds1 = dateArray[0].split("-"); // split each parts in date
var ds2 = dateArray[1].split(":"); // split each parts in time
var newDate = new Date(ds1[0], (+ds1[1] - 1), ds1[2], ds2[0], ds2[1], ds2[2]).getTime(); //parse it
var currentDate = new Date().getTime();
var diff = currentDate - newDate;
if(diff < 30000){
$(this).prop('disabled', true);
var id = $(this).attr('id');
undisable(id,diff);
}
});
Now I'd like to add a new condition: you cannot post to any user from the last minute of an hour to the first minute of the next one. So for example you cannot post from 10:59:00 to 11:01:00 (and so on for each hour of the day).
What is the cleverest way to set the if clause to do this?
What I am trying to build is something like:
if(now(minutes) is between 59 and 01){ //this is the point where I get stuck at
$('#sendbutton').prop('disabled', true); //I cannot post
}else{
$('#sendbutton').prop('disabled', false); //I can post
}
Thanks for any help!
You're right, that complicates things. Here's the code to solve your problem. Relies on setTimeouts to disable and enable the button, and you can edit the times you want to disable the button easily.
function time_disabler()
{
var time_disable = 59; // time in minutes to disable the button
var time_enable = 1; // time in minutes to enable to button
var current_mins = new Date().getMinutes(); // current time (minutes)
var current_secs = new Date().getSeconds(); // current time (seconds)
var total_seconds = current_mins * 60 + current_secs; // current time overall in seconds
var last_min_secs = time_disable*60; // time in seconds to disable the button
var first_min_secs = time_enable * 60; // time in seconds to enable the button
// if in between the two times, disable button
if((total_seconds >= last_min_secs && total_seconds < first_min_secs) || (total_seconds < first_min_secs && first_min_secs < last_min_secs))
{
$('#sendbutton').prop('disabled', true); //I cannot post
var time = (total_seconds >= first_min_secs)? first_min_secs + (60*60) - total_seconds : first_min_secs - total_seconds ;
// set time out to recall this function, which will enable it
var t = setTimeout(function (){
time_disabler();
}, time * 1000 );
} else { // if not between the times, disable it
$('#sendbutton').prop('disabled', false); //I can post
// set time out to recall this function, which will disable it
var t = setTimeout(function(){time_disabler();}, ((last_min_secs> total_seconds ? last_min_secs : last_min_secs + 60*60) - total_seconds) * 1000 );
}
}
time_disabler();
-- Old Answer --
You would just use JavaScript's getMinutes() and getSeconds():
var current_mins = new Date().getMinutes();
var current_secs = new Date().getSeconds();
current_mins += current_secs/60;
if(current_mins >= 59 || current_mins <= 1)
{
$('#sendbutton').prop('disabled', true); //I cannot post
} else {
$('#sendbutton').prop('disabled', false); //I can post
}

Executing code inside setInterval function only once per few seconds

I'm working on a simple project that is HTML and Javascript; and I have a problem with my timer.
I'm calculating the seconds between two Date() objects; and every 2 seconds, I want to get a new random number. I have a setInterval that runs every 100 ms and when I get past the 2 second mark, the code inside the if statement should run.
So my question is:
How can I make sure the code execute only once per 2 seconds in an if statement that is inside a setInterval() that runs every 100 ms?
Here is the code:
var startTime = new Date();
var endTime = new Date();
var randomNumber = 0;
var gameTimer = setInterval(function(){
//calculate seconds;
var secondsPassed = Math.round( (endTime - startTime) / 1000 );
if(modulo(secondsPassed,2) == 0){
//when the "gate" is open this keep executing every 100 mili seconds.
//but i want it to execute only once every 2 seconds.
randomNumber = Math.floor(Math.random()*lanes.length);
$(lanes[randomNumber]).append(box);
}
endTime = new Date();
}, 100);
var modulo = function (n, m) {
var remain = n % m;
return Math.floor(remain >= 0 ? remain : remain + m);
};
I think you are asking for a double-interval timer.
var interval = 100, beat = 2000, ticks = 0;
var timer = setInterval(function(){
runsEvery100ms(); // ««« Code here runs every 100 ms.
if (ticks > 0 && ticks % beat === 0) {
runsEvery2000ms(); // ««« Code here runs every 2000 ms.
ticks = 0;
}
ticks += interval;
}, interval);
Demo Fiddle here.

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