0

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)?

bofanda
  • 10,386
  • 8
  • 34
  • 57

2 Answers2

3

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!

Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
  • While I like the answer you gloss over the actual question of adding leading zeros like he already should know how to accomplish it. – Shaded May 30 '13 at 14:07
  • @Shaded: there is nothing difficult with checking if an integer is less than 10. Nevertheless, I'll add it in. – Sébastien Renauld May 30 '13 at 14:08
  • @SébastienRenauld thanks for your solution, now it's perfectly works :D – bofanda May 30 '13 at 14:13
  • @Dozent: check the updated code. I've added this shortly after Shaded pointed it out. – Sébastien Renauld May 30 '13 at 14:14
  • 1
    I'm just making sure the original question was answered. I really like the additional information, and I'll definitely use it next time I need to make a counter. Would there be a way to send a `clearInterval` to this? – Shaded May 30 '13 at 14:14
  • @Shaded: I'll add this in a moment. Also, my comments were not criticism - if you really want to know, I love having answers being improved in this fashion. The point of Stack is to provide extensive QA, not just "Have this" - and improvement suggestions are always more than welcome! – Sébastien Renauld May 30 '13 at 14:16
  • @SébastienRenauld but still, on `6th second`, the minute already is also `one`... the minutes should be counted when seconds are achieve 60 – bofanda May 30 '13 at 14:17
  • @Dozent: okay. Give me a moment and I'll get that bug sorted. – Sébastien Renauld May 30 '13 at 14:19
  • @Dozent: should be corrected using the latest version in the answer. I have not corrected the fiddle yet. – Sébastien Renauld May 30 '13 at 14:22
-1

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.

Community
  • 1
  • 1
Mike Pugh
  • 6,787
  • 2
  • 27
  • 25
  • 1
    `setInterval` will not drift as much as you querying your DOM once every `setInterval` call. Also, how exactly will he get milliseconds if your interval is 1s? Missed the point. – Sébastien Renauld May 30 '13 at 14:13
  • The moment() returns a new datetime object which resolves the milliseconds. Subtracting the two dates should give you the interval including milliseconds, regardless of your interval. You're right about the dom query, I'll update to move that out. Thanks – Mike Pugh May 30 '13 at 14:26
  • You are **still** only updating the counter once a second. – Sébastien Renauld May 30 '13 at 14:27
  • Yes - if he wants to update it more frequently he can change the interval time. It depends on what his intent is, if he wants to show the milliseconds racing up then go for it - set the interval to every 50 ms or 75 ms, or 363 ms, play with it. He knows his audience and use case better than I do. Easy enough to play with. – Mike Pugh May 30 '13 at 14:32