Need help making a Javascript countdown timer

Hi guys,

I want to make a countdown timer. I’ve seen loads of scripts for these on various sites but when I build them, they never work how I want (if at all!) so I thought, hopefully with your help, I’d build my own!

Here is my HTML…


<div class="countdownTimer">

    <div class="dashWeeks">
        <div class="dash">
            <div class="digit">0</div>
            <div class="digit">0</div>
            <span class="division">Weeks</span>
        </div>
    </div>

    <div class="dashDays">
        <div class="dash">
            <div class="digit">0</div>
            <div class="digit">0</div>
            <span class="division">Days</span>
        </div>
    </div>

    <div class="dashHours">
        <div class="dash">
            <div class="digit">0</div>
            <div class="digit">0</div>
            <span class="division">Hours</span>
        </div>
    </div>

    <div class="dashMinutes">
        <div class="dash">
            <div class="digit">0</div>
            <div class="digit">0</div>
            <span class="division">Minutes</span>
        </div>
    </div>

</div>

…and here is my stylesheet…

.countdownTimer {width:249px; height:63px; background-image:url(assets/images/countdown/countdownBg.png); position:relative; font-family:Arial, Helvetica, sans-serif;}
.dashWeeks {margin:0 0 0 34px; padding:10px 0 0; float:left; position:relative;}
.dashDays {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
.dashHours {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
.dashMinutes {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
.dash {width:37px; height:33px; background-image:url(assets/images/countdown/dashBg.png); background-repeat:no-repeat;}
.digit {width:12px; height:22px; color:#FFFFFF; font-size:20px; line-height:20px; text-align:center; float:left; display:block; padding:6px 0 0 4px;}
.division {width:37px; font-size:9px; text-transform:uppercase; text-align:center; color:#AAAAAA; clear:both; position:absolute; top:40px; left:0;}

I take it I’m going to need Javascript but how would I make it so each digit of my timer fits in the ‘digit’ div? I was hoping to add a Javascript (and maybe jQuery?) and then just change the date it counts down to each time - is that possible?

Thank you and hope to hear from you!

SM

Hi there,

In its very basic form, I would create a function which accepts a number of seconds as an argument.
It would do the following:

  • Work out what the number of seconds translated to in terms of weeks, days, months, hours and seconds.
  • Update the page (i.e. fill in the corresponding number of weeks, days, hours and seconds remaining)
  • Detract one from the total number of seconds, before updating the page again and calling itself
  • Check if the number of seconds has reached zero
  • If so, terminate with an alert.
  • If not call itself using setTimout and a delay of 1000 milliseconds

By way of an example you can see a demo here, or the code below:

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Countdown timer</title>
    <style>
      body {background:gray};
      .countdownTimer {width:300px; height:63px; background-image:url(assets/images/countdown/countdownBg.png); position:relative; font-family:Arial, Helvetica, sans-serif;}
      .dashWeeks {margin:0 0 0 34px; padding:10px 0 0; float:left; position:relative;}
      .dashDays {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
      .dashHours {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
      .dashMinutes {margin:0 0 0 10px; padding:10px 0 0; float:left; position:relative;}
      .dashSeconds {margin:0 0 0 16px; padding:10px 0 0; float:left; position:relative;}
      .dash {width:37px; height:33px; background-image:url(assets/images/countdown/dashBg.png); background-repeat:no-repeat;}
      .digit {width:12px; height:22px; color:#FFFFFF; font-size:20px; line-height:20px; text-align:center; float:left; display:block; padding:6px 0 0 4px; letter-spacing: 4px;}
      .division {width:37px; font-size:9px; text-transform:uppercase; text-align:center; color:#AAAAAA; clear:both; position:absolute; top:40px; left:0;}
    </style>
  </head>
  
  <body>
    <div class="countdownTimer">
      <div class="dashWeeks">
        <div class="dash">
          <div class="digit" id="weeks"></div>
          <span class="division">Weeks</span>
        </div>
      </div>
    
      <div class="dashDays">
        <div class="dash">
          <div class="digit" id="days"></div>
          <span class="division">Days</span>
        </div>
      </div>
    
      <div class="dashHours">
        <div class="dash">
          <div class="digit" id="hours"></div>
          <span class="division">Hours</span>
        </div>
      </div>
    
      <div class="dashMinutes">
        <div class="dash">
          <div class="digit" id="minutes"></div>
          <span class="division">Minutes</span>
        </div>
      </div>
      
      <div class="dashSeconds">
        <div class="dash">
          <div class="digit" id="seconds"></div>
          <span class="division">Seconds</span>
        </div>
      </div>
    </div>
  
    <script>
      (function () {
        "use strict";
        
        var Timer = {
          totalSeconds: 5000000,
          weeksDiv: document.getElementById("weeks"),
          daysDiv: document.getElementById("days"),
          hoursDiv: document.getElementById("hours"),
          minutesDiv: document.getElementById("minutes"),
          secondsDiv: document.getElementById("seconds"),
          
          pad: function(num, size) {
            var s = num + "";
            while (s.length < size) s = "0" + s;
            return s;
          },
          
          updateTime: function(){
            this.weeks = Math.floor((this.totalSeconds % 31536000) / 604800);
            this.days = Math.floor(((this.totalSeconds % 31536000) % 604800) / 86400);
            this.hours = Math.floor(((this.totalSeconds % 31536000) % 86400) / 3600);
            this.minutes = Math.floor((((this.totalSeconds % 31536000) % 86400) % 3600) / 60);
            this.seconds = (((this.totalSeconds % 31536000) % 86400) % 3600) % 60;
          },
          
          updateDisplay:function(){
            this.weeksDiv.innerHTML = this.pad(this.weeks, 2);
            this.daysDiv.innerHTML = this.pad(this.days, 2);
            this.hoursDiv.innerHTML = this.pad(this.hours, 2);
            this.minutesDiv.innerHTML = this.pad(this.minutes, 2);
            this.secondsDiv.innerHTML = this.pad(this.seconds, 2);
          },
          
          countdown: function(){
            Timer.updateTime();
            Timer.updateDisplay();
            if (Timer.totalSeconds === 0){
              window.alert("Time's up!");
            } else {
              Timer.totalSeconds -= 1;
              window.setTimeout(Timer.countdown, 1000);
            }
          }
        };
        Timer.countdown();
      }());
    </script>
  </body>
</html>

I hope that helps you. If you have any questions, just let me know.

Hey Pullo!
Wow, that’s mega - thank you very much for a very detailed and informative response :slight_smile:
Is there a way your syntax can have a date field so instead of having to calculate the number of seconds to countdown, I can just insert the relevant date and time and the script works out the number of seconds- if that makes sense!
Sorry, I’m absolutely clueless with JavaScript as I’m sure you can see but thank you for helping me learn how it works, great stuff! :slight_smile:

No probs :slight_smile:

Sure, just change this:

totalSeconds: 5000000,

to this:

totalSeconds: Math.floor((new Date(("October 13, 2014 11:13:00") - new Date())/1000),

Where the first date is the date in the future you wish the countdown to run until.
What you are effectively doing is creating two date objects (a future one and a current one), then subtracting one from the other and ending up with the number of milliseconds between the two.
Divide that by one thousand and you are back to your number of seconds.

Just refactored the code a little:

(function () {
  "use strict";
  
  var Timer = {
    weeksDiv: document.getElementById("weeks"),
    daysDiv: document.getElementById("days"),
    hoursDiv: document.getElementById("hours"),
    minutesDiv: document.getElementById("minutes"),
    secondsDiv: document.getElementById("seconds"),
    
    pad: function(num, size) {
      var s = num + "";
      while (s.length < size) s = "0" + s;
      return s;
    },
    
    updateTime: function(){
      Timer.weeks = Math.floor(Timer.totalSeconds / 604800);
      Timer.days = Math.floor((Timer.totalSeconds % 604800) / 86400);
      Timer.hours = Math.floor((Timer.totalSeconds % 86400) / 3600);
      Timer.minutes = Math.floor(((Timer.totalSeconds % 86400) % 3600) / 60);
      Timer.seconds = Math.floor(((Timer.totalSeconds % 86400) % 3600) % 60);
    },
    
    updateDisplay:function(){
      Timer.weeksDiv.innerHTML = Timer.pad(Timer.weeks, 2);
      Timer.daysDiv.innerHTML = Timer.pad(Timer.days, 2);
      Timer.hoursDiv.innerHTML = Timer.pad(Timer.hours, 2);
      Timer.minutesDiv.innerHTML = Timer.pad(Timer.minutes, 2);
      Timer.secondsDiv.innerHTML = Timer.pad(Timer.seconds, 2);
    },
    
    countdown: function(){
      Timer.updateTime();
      Timer.updateDisplay();
      if (Timer.totalSeconds === 0){
        window.alert("Time's up!");
      } else {
        Timer.totalSeconds -= 1;
        window.setTimeout(Timer.countdown, 1000);
      }
    }, 
    
    init: function(toDate){
      Timer.totalSeconds = Math.floor(toDate - new Date())/1000;
      Timer.countdown();
    }        
  };
  
  var toDate = new Date("April 30, 2014 00:00:00")
  Timer.init(toDate);
}());

Fantastic! Thank you so much Pullo, you’ve really helped me out big time and you’re a genuis!

Thank you again, top shooter! :slight_smile:

You’re welcome :slight_smile:
It was a fun script to make.

hi, i am trying to do a countdown timer. i got some images and when i click a image only the timer needs to be started. and i want timer to stop at 0 and not -1,-2,…etc.
hope some one helps me…

Hi kadi,

The code above should stop at zero.

Clicking on an image to start the timer should be as simple as:

var toDate = new Date("April 30, 2014 00:00:00"),
    img = document.getElementById("myImg");

img.onclick = function(){
  Timer.init(toDate);
}

i’m using the code below but its going below 0 when it is in background and everything else is perfect. i am testing on a mobile device and when i minimise and then resume, the timer is still running in background. when it is not in use or minimised, the timer needs to stop and when resumed it needs to start again. most probably like a game timer.Hope someone can help me on this


<!DOCTYPE html>
<html>
<head>

<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">

<title>Image Match Game</title>


<style type="text/css">

body {
  background-color: #EEEEEE;
  margin: 0;
}

#match-holder {
    margin: 100px auto;
    width: 900px;
}

#match-holder IMG{
    width: 200px;height:200px;
}


</style>

</head>
<body>

<div id="match-holder">
        <img class="birds" src="https://lh4.googleusercontent.com/-FmW-yW_iThc/UYHsbbbBK0I/AAAAAAABXGE/g_vGb4Gh7lE/w497-h373/97604-beautiful-birds-blue-bird.jpg" alt="" />
        <img class="cats" src="http://images.wisegeek.com/young-calico-cat.jpg" alt="" />
        <img class="cats" src="http://avivaromm.com/romm/wp-content/uploads/2013/07/0404_milk.jpg" alt="" />
        <img class="birds" src="http://www.communityjournal.net/wp-content/uploads/2012/05/seeds.jpg" alt="" />
    </div>
<div>
<br />
<span id="count" ></span>

<script type="text/javascript">
/*<![CDATA[*/

var zxcMatch={

 Reset:function(id){
  var o=this[id],z0=0;
  if (o){
   clearTimeout(o.to);
   o.time[1]=null;
   for (;z0<o.imgs.length;z0++){
    o.imgs[z0].style.visibility='visible';
   }
   o.cnt=z0/2;
   o.lst=null;
  }
 },

 init:function(o){
  var id=o.ParentID,imgs=document.getElementById(id).getElementsByTagName('IMG'),z0=0;
  o.imgs=imgs;
  for (;z0<imgs.length;z0++){
   this.addevt(imgs[z0],'mouseup','match',o,imgs[z0]);
  }
  o.time=[typeof(o.Timer)=='function'?o.Timer:null];
  o.cnt=z0/2;
  this[id]=o;
 },

 match:function(o,img){
  if (o.time[0]&&!o.time[1]){
   o.time[1]=new Date();
   o.to=setInterval(function(){ o.time[0](o,Math.floor((new Date()-o.time[1])/1000)); },1000);
  }
  if (!o.lst){
   o.lst=img;
  }
  else {
   if (o.lst.className==img.className&&o.lst!=img){
    img.style.visibility=o.lst.style.visibility='hidden';
    o.cnt--;
    if (o.cnt==0){
     clearTimeout(o.to);
     o.time[1]=null;
     o.Complete();
    }
   }
   else {
    alert('try again');
   }
   o.lst=null;
  }
 },

 addevt:function(o,t,f,p,p1){
  var oop=this;
  o.addEventListener?o.addEventListener(t,function(e){ return oop[f](p,p1);},false):o.attachEvent?o.attachEvent('on'+t,function(e){ return oop[f](p,p1); }):null;
 }


}

zxcMatch.init({
 ParentID:'match-holder',
 Timer:function(o,sec){
  document.getElementById('count').innerHTML=30-sec;
  if (sec>29){
    alert('Time Out');
    zxcMatch.Reset('match-holder');
  }
 },
 Complete:function(){
//  window.top.location='http://www.vicsjavascripts.org.uk/';
 }
});
/*]]>*/
</script>
</body>
</html>