I want to implement a count-up timer JS code that starts counting at each load page from 0. The code which I've now is like this:
var secondsTotal = 0;
setInterval(function() {
++secondsTotal;
var minutes = Math.floor(secondsTotal / 60);
var seconds = Math.floor(secondsTotal) % 60;
var milliseconds = Math.floor(secondsTotal) % 1000;
document.getElementById('counter').innerHTML = minutes + ":" + seconds + "." + milliseconds;
}, 1000);
The output format should be: 00:00.0
mm:ss.ms
So, how to output the result like above format (minutes and seconds should be exactly printed in two digits format)?
If you want to do it per-page, you're almost there. Right now, your code does not allow you to track milliseconds, as your setInterval runs every second. What I would recommend instead is something like this:
(function() {
var counter = 0,
cDisplay = document.getElementById("counter");
format = function(t) {
var minutes = Math.floor(t/600),
seconds = Math.floor( (t/10) % 60);
minutes = (minutes < 10) ? "0" + minutes.toString() : minutes.toString();
seconds = (seconds < 10) ? "0" + seconds.toString() : seconds.toString();
cDisplay.innerHTML = minutes + ":" + seconds + "." + Math.floor(t % 10);
};
setInterval(function() {
counter++;
format(counter);
},100);
})();
This does a couple of things to allow your code to run 10 times per second:
The output element, #counter, is cached and not retrieved every iteration
The formatting is kept to arithmetic operations only - modulo and division.
This now also adds leading zeroes.
If you would like to keep this counter running page-per-page, consider using document.cookies to pass the final value from page to page.
Fiddle
This serves as a good first version. However, you may want to:
Pause/re-start your timer
Reset your timer
Have multiple timers
For this reason, I will add a slightly more complex form of the above code, which will allow you to manage multiple timers. This will make use of a few OO concepts. We will use a TimerManager object to "host" our timers, and each Timer object will have a link to the manager.
The reason for this is because every timer will depend on the same setInterval() by doing it this way, rather than to have multiple setInterval() calls. This allows you to cut down on wasted clock cycles.
More on this in about 5 minutes!
Counting seconds that way isn't guaranteed to be accurate. The setInterval method can drift on you based upon the JS engine's ability to complete its other tasks. Not sure what your use case is, such as how long you expect to count up, but it's worth taking note of. See Will setInterval drift? for a detailed explanation.
I'd recommend you check out the momentjs plugin # http://momentjs.com/ and update your code to something like the following
var startTime = moment();
var el = document.getElementById('counter');
setInterval(function() {
var ms = moment().diff(startTime),
min = moment.duration(ms).minutes(),
sec = moment.duration(ms).seconds();
ms = moment.duration(ms).milliseconds();
min = (min < 10) ? "0" + min.toString() : min.toString();
sec = (sec < 10) ? "0" + sec.toString() : sec.toString();
ms = ms.toString().substring(0,2); // change this if you want to expand ms counter display
el.innerHtml = min + ":" + sec + "." + ms;
}, 50);
You're free to update the interval, and your milliseconds display without adjusting your calculations.
Related
I have double checked and tested on jshint for syntax errors and such. I have also compared my code to others who created the same clock, but did not see any differences that would cause my clock to crash. I do not understand what is causing this problem.
$(document).ready(function(){
function displayTime() {
var currentTime = new Date();
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
var miridiem = "AM";
var clockDiv = document.getElementById('clock');
if(seconds < 10) {
seconds = "0" + seconds
}
if(minutes < 10) {
minutes = "0" + minutes
}
if (hours > 12) {
hours = hours - 12
miridiem = "PM"
}
if (hours === 0) {
hours = 12
}
clockDiv.textContent = hours + ":" + minutes + ":" + seconds + " " + miridiem;
setInterval(displayTime, 1000);
}
displayTime();
});
<body>
<div id="clock"></div>
<script src="https://code.jquery.com/jquery-3.0.0.min.js" integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0=" crossorigin="anonymous"></script>
</body>
Warning: snippet will eat your memory. Don't forget to stop it.
https://jsfiddle.net/9cp9m43h/
You're just misunderstanding the usage of setInterval and setTimeout.
As some commenters mentioned, you could just change your current implementation to use setTimeout and it would function pretty well.
However, in my opinion, the best solution would be to change the way your code works, so that setInterval works correctly:
$(document).ready(function(){
function displayTime() {
var currentTime = new Date();
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var seconds = currentTime.getSeconds();
var miridiem = "AM";
var clockDiv = document.getElementById('clock');
if(seconds < 10) {
seconds = "0" + seconds
}
if(minutes < 10) {
minutes = "0" + minutes
}
if (hours > 12) {
hours = hours - 12
miridiem = "PM"
}
if (hours === 0) {
hours = 12
}
clockDiv.textContent = hours + ":" + minutes + ":" + seconds + " " + miridiem;
}
displayTime();
setInterval(displayTime, 1000);
});
I feel this is better because:
this is what setInterval was designed for: performing the same action over and over at a specific interval.
calling setTimeout manually to reset the timer leaves you open to some clock skew; if it takes a millisecond for your displayTime to run before it sets the timeout, then after 1000 seconds you're probably going to be about 1 second off.
a function called displayTime() sounds like all it's doing is displaying the time--there's nothing to hint that it's also creating a long-term side-effect. The separation of concerns feels better if the timer is set outside of that method.
The effects of displayTime() are easier to test independently when it's not creating asynchronous side-effects.
I think your setInterval() is in the wrong place. You placed it inside the function, which is registering 60 interval monitors per minute so the memory is crashing. If you wanted to trigger the next timeout after the function has been called, you can do that using setTimeout(), within the displayTime() function. But if you do setInterval(), you want that to be called at the same level that your initial displayTime() function is called.
See my fiddle: https://jsfiddle.net/9cp9m43h/3/
every time displayTime() is called it starts a new Interval that calls displayTime() every second.
Therefore every second the function is called twice as often as the time before. After 60 Seconds this is Math.pow(2, 60) //=> 1152921504606847000 times.
Hmm, i'm having a hard time figuring out how it crashed with the setInterval() within the displayTime() function, but working completely fine outside the function.
Because in this case displayTime() is not calling itself not even a roundtrip over setInterval. So it stays a single Interval, and therefore a single function-call every second.
numberOfSeconds=1*60,
r=document.getElementById('clock');
var t = setInterval(function(){
numberOfSeconds--;
var minutes=Math.floor(numberOfSeconds/60),seconds=(numberOfSeconds%60)+'';
r.textContent='Registration closes in '+minutes+':'+(seconds.length>1?'':'0')+seconds;
if (numberOfSeconds <= 0) {
clearInterval(t);
alert('boom');
}
},1000);
html section
<div id="clock"></div>
how i can add milliseconds to this reverse count down timer/counter script.
i want it like 00:00:00 <== milliseconds in last.
}},1000 / 20);
However above little change in last of script made seconds into milliseconds but i can't figure out how i can adjust it with seconds like MM:SS:MS 00:00:00
Any Help will be appreciated..!
That setInterval will have to be set to 1 (ms), if you need to see the milliseconds. 1000ms = 1s. So I believe MM:SS:MS would look more like 00:00:000.
I do not think it's possible. i did a test and the results show that js cannot be as fast to set 1millisecond to setInterval. setting it to 1ms - 15ms will output the same results.
normaly the code below should work the way you wanted.
var m = 60*1000, r = document.getElementById("clock");
var t = setInterval(function () {
m--;
var min = Math.floor(m / 60000),
sec = Math.floor((m % 60000) / 1000);
mil = (m % 60000) % 1000; r.innerHTML = min + ":" + sec + ":" + mil;}, 1)
Maybe the problem comes from my computer (maybe it is slow).
if you ever want the test script, tell it in comment so i will give it to you in order you'll test it by yourself
I'm trying to make a countdown timer for each row of a table based on a hidden field containing the ammount of seconds to finish. Here is what I have done so far:
function countdownProcedure() {
var interval = 1000;
var i = 0;
var seconds;
$(".rfqTbl tr").each(function() {
if(i > 0) {
seconds = $(this).find("#sqbTimestamp").text();
var days = Math.floor(seconds / (60*60*24));
seconds -= days * 60 * 60 * 24;
var hours = Math.floor(seconds / (60*60));
seconds -= hours * 60 * 60;
var minutes = Math.floor(seconds / 60);
seconds -= minutes * 60;
if(days < 1) { days=""; }
$(this).find("#countDown").html(days + "<pre> Days</pre> " + hours + "<pre>:</pre>" + minutes + "<pre>:</pre>" + seconds);
if(days > 1) {
$(this).find("#countDown").css({
'color':'#2A7F15',
'font-weight':'bold'
});
};
if(days < 1) {
$(this).find('#countDown').css('color','red');
$(this).find('#countDown pre:nth-of-type(1)').css('display','none');
}
if(seconds < 10) {
$(this).find("#countDown").append(" ");
};
if(minutes < 60){ interval = 1000; };
}
i++;
});
setInterval(countdownProcedure,interval);
};
However, my problem is that I'm trying to get this function to run (realistically every second or 30) so that the time shown would update and hence 'countdown'. The problem I am having is in firefox and safari the browsers are just hanging after the first countdown and chrome is doing nothing (I guess it has a safe guard to prevent it from hanging).
Any help would be much appreciated!
You are running a multitude of setInterval() calls, so the event queue gets crowded with your function.
I think, what you mean is more like setTimeout() at the end of your function.
function countdownProcedure(){
// all your logic
setTimeout(countdownProcedure,interval);
};
The difference is, that setInterval() will run your code every x seconds, until you tell it to stop.
setTimeout() on the other hand, just runs your code once after x seconds.
Change all ids for clases Ex: #sqbTimestamp for .sqbTimestamp
in an HTML document, should exists only 1 element with some id, if you set multiple elements with same id, unexpected results (as browser hanging) can occurrs.
Also, you are setting days="" and then do the following compare if (days > 1)
I think your algorithm is wrong. You are recursively setting intervals which are calling themselves every time and setting new intervals and so on...
You must change your algorithm a bit to get it clean.
I'm using script below to countdown from given time and display how many hours+minutes+seconds left for timeout on the script in real-time.
Counting down woks perfectly fine but the problem I'm facing is, when using next and previous buttons on browsers, the time doesn't get refreshed and I see old time instead. It either shows previous time or later.
I'm aware that next and previous buttons on browsers don't refresh pages but how can I overcome this issue?
JS
function timeout_warning(login_timeout)
{
var counter = 0;
var total_seconds = 0;
var colour = '';
var interval_id = '';
interval_id = setInterval(function ()
{
counter++;
total_seconds = login_timeout - counter;
hours = parseInt(total_seconds / 3600 ) % 24;
minutes = parseInt(total_seconds / 60 ) % 60;
seconds = parseInt(total_seconds % 60, 10);
remaining = (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes) + ":" + (seconds < 10 ? "0" + seconds : seconds);
if (minutes == 0 && seconds == 0)
{
document.getElementById('font_timeout').innerHTML = 'Timeout';
window.clearInterval(interval_id);
}
else
{
document.getElementById('font_timeout').innerHTML = remaining + 'sec';
}
}, 1000);
}
HTML BODY
<body onload="timeout_warning('1800')">
Without a live example I can only give an opinion to the solution. You might want to us JavaScript to load the remaining time from a cookie so that when a browser arrow is clicked the code will pull the time from the cookie and not from the cached data.
A solution has already been posted on this and uses a form to store data in the page to see if the user has pressed the back button. It sets some form data and if the page goes back, it can tell if that data is already set, and if it is, it needs to force a reload (so your timer will start again).
I'm writing a Greasemonkey script where I want to know when it was last run. To do this, I wanted to store the current time with GM_setValue and compare that time to the time when the script is run again.
However, it seems that the Date().getTime() results won't pass to GM_setValue. For instance if you run:
var newtime = new Date().getTime();
GM_setValue('lastrun', newtime);
alert(GM_getValue('lastrun'));
There's obviously errors since the alert box won't pop up. However if you replace the first line with:
var newtime = 1;
you then get 1 returned in the alert box like you would expect.
That pretty much just isolates the date format causing the issue here. Any ideas on how to deal with this, or better ways to save dates between times a script has run?
I had a similar issue. The number is too large to be stored as a firefox cookie value. My solution was to limit the precision to the second (divide by 1000, drop remainder) and subtract 43 years (1356998400 seconds) to bring the date measured from to Midnight Jan 1st 2013 so my code looks like this:
var time = Math.floor((new Date().getTime() / 1000) - 1356998400);
GM_setValue("runTime", time);
and the retrieval looked like:
var time = GM_getValue("runTime", 0);
if (time != 0) {
var cur = Math.floor((new Date().getTime() / 1000) - 1356998400);
var cur = cur - time;
var sec = cur % 60;
var min = Math.floor(cur / 60);
console.log("Script took " + min + ":" + sec);
}