Skip to content Skip to sidebar Skip to footer

Multiple Countdown Timers On One Page

Currently working on a project that requires two timers on one page. The timers need to have a start button and both have different timings (i.e. timer1 lasts 10 secs and timer2 la

Solution 1:

There are few things you're doing that prevent you from expanding the code. If you want a reusable timer, you can't hard set the variables it will use. So first thing is to get rid of the three variables at the top and recreate them WITHIN the scope of the function.

That way, every time the function is called, a new set of variables is created for its execution.

The minutes and seconds are probably best passed as parameters and interval should be defined within the scope of function.

Secondly you are setting the click handler BOTH inline and within the script. Get rid of one of them (preferably get rid of the inline version).

Then, you have a timer variable as a parameter for the click handler and setInterval but never used. That variable will be set to the click event on the event handler (and again, is not being used) and will be undefined on setInterval. So they really shouldn't be there.

A performance issue, you may want to know about is that you are doing a DOM lookup for the counters EVERY second. You should get it once per function call at the beginning and cache it.

At that point, you function would look more or less like this

function countdown(element, minutes, seconds) {
    // Fetch the display element
    var el = document.getElementById(element);

    // Set the timer
    var interval = setInterval(function() {
        if(seconds == 0) {
            if(minutes == 0) {
                (el.innerHTML = "STOP!");     

                clearInterval(interval);
                return;
            } else {
                minutes--;
                seconds = 60;
            }
        }

        if(minutes > 0) {
            var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
        } else {
            var minute_text = '';
        }

        var second_text = seconds > 1 ? '' : '';
        el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + '';
        seconds--;
    }, 1000);
}

And your setup more or less like this

//Start as many timers as you want

var start1 = document.getElementById('timer1');
var start2 = document.getElementById('timer2');

start1.onclick = function() {
    countdown('countdown1', 0, 15);
}

start2.onclick = function() {
    countdown('countdown2', 0, 10);
}

Of course, you need the extra button and counter

<div id='countdown1'></div>
<div id='countdown2'></div>
<input id="timer1" type="button" value="Start timer 1" />
<input id="timer2" type="button" value="Start timer 2" />

Working example: http://codepen.io/anon/pen/Jmpcq/?editors=101

-- Note: for precise timers, setInterval() may not be a good option because the precise interval is not guaranteed and time tracked by it may be delayed after a while. For applications where precise time is critical, there are other methods (e.g. https://sitepoint.com/creating-accurate-timers-in-javascript & https://html5rocks.com/en/tutorials/webperformance/usertimin), thanks @KaiKarver for pointing out in the comments.


Solution 2:

Long but it works

let d = document,
    id = 'getElementById',
    time = {
//Multiple Timers
//[current time, time setting, (pause/running), HTML section#timer]
      timer1: ['0:10', '0:10', 0, d[id]('timer1')],
      timer2: ['2:30', '2:30', 0, d[id]('timer2')],
      timer3: ['5:00', '5:00', 0, d[id]('timer3')],


//Manage Timer Functions
      reset: function(t) {time[t][0] = time[t][1];},
      pause: function(t) {time[t][2] = 0;time.state(t,'pause');time.button(t,'resume');},
      resume: function(t) {time[t][2] = 1;time.state(t,'running');time.button(t,'pause');},
      set: function(t,s) {time[t][0] = s; time[t][1] = s;},
      state: function(t,s) {time[t][3].setAttribute('state',s);},
      button: function(t,s) {time[t][3].querySelector('div').innerHTML = s;},
      cancel: function(t) {time[t][2] = 0;time.reset(t);time.state(t,'');time.button(t,'start');time.setTimer(t);},
      start: function(t) {time.reset(t);time[t][2] = 1;time.state(t,'running');time.button(t,'pause');},
      getTimers: function() {return Object.keys(time).filter(function (n) {return n.indexOf("ti")==0;});},
      setTimer: function(t) {time[t][3].querySelector('span').innerHTML = time[t][0]},
      setTimers: function(x) {
        let times = time.getTimers();
        for (var i=0,t;i<times.length;i++) {t=times[i];
              if(time[t][2]||x){time[t][3].querySelector('span').innerHTML = time[t][0]}
        }
  },
};

//handle seconds passed
function convertSeconds(s=0) {return new Date(s*1000).toISOString().substr(11,8).replace(/^(00:0(?=[1-9])|00:|0)/gm, '')}
function toSeconds(t) {t=t.split(':').reverse();return (t[2]*3600||0)+(t[1]*60||0)+t[0]*1||0;}

//set HTML times onLoad
time.setTimers(1)


function runTimer(times){times = time.getTimers();time.setTimers();
    function run(t,s,l){if(t&&t[2]){s=toSeconds(t[0]);t[0]=s?convertSeconds(s-1):'00:00'&&(time.cancel(l));}}
    for (var i=0,t;i<times.length;i++) {run(time[times[i]],'',times[i])}
}

//run timer every second reguardless of whether timer is paused or running
setInterval(runTimer, 1000)
body {
  background: #e6e9f0;
  user-select: none;
  font-family: "SF Pro Display", Helvetica Neue, Arial, Helvetica, Geneva, sans-serif;
  font-size: 14px;
}
div, span {display: inline-block;}
span {min-width: 60px;}
#time > section {
  padding: 10px 20px;
  background: white;
  margin: 10px;
  border-radius: 4px;
  transition: .15s ease-in-out 0s;
  text-transform: capitalize;
}
#time > section:hover {box-shadow: 0px 0px 0px 2px #A8D1FD;}
#time > section > div{text-shadow: 0 1px 1px rgba(0,0,0,0.3);transition: .1s ease-in-out 0s;}
#time > section > div:nth-of-type(2){background: #cfd3dd;opacity: 1;}
#time > section[state=""] > div:nth-of-type(2) {opacity: 0;}
#time > section > div{
  background: #368ad2;
  color: white;
  padding: 6px 10px;
  margin: 0 5px;
  min-width: 50px;
  text-align: center;
  border-radius: 4px;
}
<section id="time">
  <section id="timer1" state="">
    <span>0:00</span>
    <div onClick="time[this.innerHTML]('timer1')">start</div>
    <div onClick="time.cancel('timer1')">cancel</div>
  </section>
  <section id="timer2" state="">
    <span>0:00</span>
    <div onClick="time[this.innerHTML]('timer2')">start</div>
    <div onClick="time.cancel('timer2')">cancel</div>
  </section>
  <section id="timer3" state="">
    <span>0:00</span>
    <div onClick="time[this.innerHTML]('timer3')">start</div>
    <div onClick="time.cancel('timer3')">cancel</div>
  </section>
</section>

Solution 3:

var interval;

var countdown1 = {
    minutes:0,
    seconds: 10
};

var countdown2 = {
    minutes:0,
    seconds: 2
}

function countdown(element) {
    alert(element);
    var cd;
    element === 'countdown1' ? cd = countdown1 : cd = countdown2;
    interval = setInterval(function(timer) {
        var el = document.getElementById(element);
        if(cd.seconds == 0) {
            if(cd.minutes == 0) {
                (el.innerHTML = "STOP!");     

                clearInterval(interval);
                return;
            } else {
                cd.minutes--;
                cd.seconds = 60;
            }
        }
        if(cd.minutes > 0) {
            var minute_text = cd.minutes + (cd.minutes > 1 ? ' minutes' : ' minute');
        } else {
            var minute_text = '';
        }
        var second_text = seconds > 1 ? '' : '';
        el.innerHTML = minute_text + ' ' + cd.seconds + ' ' + second_text + '';
        cd.seconds--;
    }, 1000);
}
var start = document.getElementById('start');


 <div id='countdown'></div>
 <input type="button" onclick="countdown('countdown1');this.disabled = true;" value="Start" />
 <div id="countdown1"></div>

 <input type="button" onclick="countdown('countdown2');this.disabled = true;" value="Start" />
 <div id="countdown2"></div>

fiddle: http://jsfiddle.net/dn3hJ/


Post a Comment for "Multiple Countdown Timers On One Page"