Jump to content

How to display a countdown timer with JavaScript

+ 1
  dannyg1's Photo
Posted Sep 02 2009 02:08 PM

Countdown timers can take many forms. This example application sets the turn of the new yearin the user's time zone as the "zero hour" for the timer, and displaysa constantly updated display of the days, hours, minutes, and secondsuntil that time.An onload event handler in the page invokes the countDown() function by way of the setInterval() method:

window.onload = function() {setInterval("countDown()", 1000)};

The display is updated approximately every second because the setInterval() method repeatedly invokes the countDown() function until a script cancels the timer.The display of the timer can be in a text input field (all scriptable browsers), swappableimages, or body text. This example uses swappable images because itlends itself to the most flexible page designs of the choices. The following figure shows the output.

Countdown timer with swappable image
Attached Image




The following example shows the complete HTML document for this application, including the HTML and scripts.

A countdown timer application
<html>
 <head>
 <title>Recipe 15.9</title>
 <style type="text/css">
 table {border-spacing: 0}
 td {border: 2px groove black; padding: 7px; background-color: #ccffcc}
 th {border: 2px groove black; padding: 7px; background-color: #ffffcc}
 .ctr {text-align:center}
 </style>
 <script type="text/javascript">
 if (document.images) {
     var imgArray = new Array();
     imgArray[0] = new Image(60,120);
     imgArray[0].src = "digits/0.gif";
     imgArray[1] = new Image(60,120);
     imgArray[1].src = "digits/1.gif";
     imgArray[2] = new Image(60,120);
     imgArray[2].src = "digits/2.gif";
     imgArray[3] = new Image(60,120);
     imgArray[3].src = "digits/3.gif";
     imgArray[4] = new Image(60,120);
     imgArray[4].src = "digits/4.gif";
     imgArray[5] = new Image(60,120);
     imgArray[5].src = "digits/5.gif";
     imgArray[6] = new Image(60,120);
     imgArray[6].src = "digits/6.gif";
     imgArray[7] = new Image(60,120);
     imgArray[7].src = "digits/7.gif";
     imgArray[8] = new Image(60,120);
     imgArray[8].src = "digits/8.gif";
     imgArray[9] = new Image(60,120);
     imgArray[9].src = "digits/9.gif";
 }
 
 var nextYear = new Date().getYear() + 1;
 nextYear += (nextYear < 1900) ? 1900 : 0;
 var targetDate = new Date(nextYear,0,1);
 var targetInMS = targetDate.getTime();
 var oneSec = 1000;
 var oneMin = 60 * oneSec;
 var oneHr = 60 * oneMin;
 var oneDay = 24 * oneHr;
 
 function countDown() {
     var nowInMS = new Date().getTime();
     var diff = targetInMS - nowInMS;
     var scratchPad = diff / oneDay;
     var daysLeft = Math.floor(scratchPad);
     // hours left
     diff -= (daysLeft * oneDay);
     scratchPad = diff / oneHr;
     var hrsLeft = Math.floor(scratchPad);
     // minutes left diff -= (hrsLeft * oneHr);
     scratchPad = diff / oneMin;
     var minsLeft = Math.floor(scratchPad);
     // seconds left diff -= (minsLeft * oneMin);
     scratchPad = diff / oneSec;
     var secsLeft = Math.floor(scratchPad);
     // now adjust images
     setImages(daysLeft, hrsLeft, minsLeft, secsLeft);
 }
 
 function setImages(days, hrs, mins, secs) {
     var i;
     days = formatNum(days, 3);
     for (i = 0; i < days.length; i++) {
         document.images["days" + i].src = imgArray[parseInt(days.charAt(i))].src;
     }
     hrs = formatNum(hrs, 2);
     for (i = 0; i < hrs.length; i++) {
         document.images["hours" + i].src = imgArray[parseInt(hrs.charAt(i))].src;
     }
     mins = formatNum(mins, 2);
     for (i = 0; i < mins.length; i++) {
         document.images["minutes" + i].src = imgArray[parseInt(mins.charAt(i))].src;
     }
     secs = formatNum(secs, 2);
     for (i = 0; i < secs.length; i++) {
         document.images["seconds" + i].src = imgArray[parseInt(secs.charAt(i))].src;
     }
 }
 
 function formatNum(num, len) {
     var numStr = "" + num;
     while (numStr.length < len) {
         numStr = "0" + numStr;
     }
     return numStr
 }
 
 window.onload = function() {setInterval("countDown()", 1000)};
 </script>
 </head>
 <body style="margin-left: 10%; margin-right: 10%">
 <h1>New Year's Countdown Timer</h1>
 <hr />
 
 <table cellspacing="5" cellpadding="5">
 <tr>
 
     <td align="right">
         <img name="days0" src="digits/0.gif" height="120" width="60" alt="days">
         <img name="days1" src="digits/0.gif" height="120" width="60" alt="days">
         <img name="days2" src="digits/0.gif" height="120" width="60" alt="days">
     </td>
     <td align="left">
         <img src="digits/days.gif" height="120" width="260" alt="days">
     </td>
 </tr>
 <tr>
     <td align="right">
 
         <img name="hours0" src="digits/0.gif" height="120" width="60" alt="hours">
         <img name="hours1" src="digits/0.gif" height="120" width="60" alt="hours">
     </td>
     <td align="left">
         <img src="digits/hours.gif" height="120" width="360" alt="hours">
     </td>
 </tr>
 <tr>
     <td align="right">
         <img name="minutes0" src="digits/0.gif" height="120" width="60" alt="minutes">
         <img name="minutes1" src="digits/0.gif" height="120" width="60" alt="minutes">
     </td>
     <td align="left">
         <img src="digits/minutes.gif" height="120" width="450" alt="minutes">
 
     </td>
 </tr>
 <tr>
     <td align="right">
         <img name="seconds0" src="digits/0.gif" height="120" width="60" alt="seconds">
         <img name="seconds1" src="digits/0.gif" height="120" width="60" alt="seconds">
     </td>
     <td align="left">
         <img src="digits/seconds.gif" height="120" width="460" alt="seconds">
     </td>
 </tr>
 </table>
 
 </body>
 </html>
 
 
 					  

For this example, the target date of the countdowntimer is the start of the next year in the user's local time zone. TheHTML output display is a rudimentary table with place holders for thedigit images. Because this application works with browsers that mayexperience CSS formatting problems, we use the old-fashioned, but stillsupported, align attribute in table cells and name attribute in img elements. The table is delivered to the browser with all of the swappable images set to the zero digit representation.

Thescript portion of the page begins by precaching the images thatrepresent the numbers to prevent any delay the first time they areneeded. Ten images, each the same height and width, are loaded into thebrowser's image cache while the page loads.

Several functions will execute repeatedly, and they benefit from the one-time predefinition of constants as global variables.

The function that executes repeatedly, countDown(), performs the datemath by comparing the current clock setting (read approximately everysecond) against the target date. Invoked by way of the window.setInterval() method, the countDown() function executes repeatedly once every second (plus or minus system latency).

Next is the setImages() function, which adjusts the swappable img element src properties. This function must convert the numeric values passed from countDown() into the URLs for the images. Calling formatNum() for each countdown component returns a string version of the number, including a leading zero where necessary.

This application is a good demonstration of a situation where it makes sense to use setInterval() to drive the repeated action. While setTimeout() is intended for a single invocation of a function after some delay, setInterval() automatically invokes a function repeatedly.

Repeted calls to the countdowntimer can exhibit less than smooth running. If you watch this coderun for several seconds, you will notice an occasional and randomunevenness to the flipping of the seconds. You can improve thesmoothness by shortening the interval delay (to 100, for example), butthis means that the function is being invoked 10 times per second,which could impact other script processing in your page. You canexperiment with different settings to achieve the balance that feelsbest for your application.

So far, we have focused on the user's local time zone, but there may beother cases in which you want to peg the target date and time to aunique event occurring some-place on the planet, such as a corporatepress conference announcing a new product release. To keep the timingaccurate, you need to perform some additional calculations to get thetime zone issues under control so that users from Australia toGreenland will see the exact same countdown times leading up to thesingular event.

The codingfor this is simple, but the timekeeping may not be. To peg the targettime and date to a universal point in the future, change the globalvariable declarations shown in Example 15-5 from this:

var targetDate = new Date(nextYear,0,1);
 var targetInMS = targetDate.getTime();

to this:

var targetInMS = Date.UTC(nextYear, 0, 1, 0, 0, 0);

This is for the stroke ofmidnight on New Year's Eve at Greenwich Mean Time (GMT). If you haveanother date and time, simply plug the values into the six parametersin the order of four-digit year, month (zero-based), date, hour,minute, and second, but at Greenwich Mean Time. For example, if youplan to offer a web cast of a recital at 8 P.M. in Los Angeles onJanuary 10, 2008, you need to determine what that time is in GMT sothat you can provide a countdowntimer on the announcement page. Los Angeles is in the Pacific TimeZone, and in that part of the year, the zone is Pacific Standard Time.The PST zone is eight hours earlier than GMT. When it's 8 P.M. in LosAngeles, it's 4 A.M. the next day at GMT. Thus, you'd set the targettime for 4 A.M. on the 11th of January (month index is 2) like this:

var targetInMS = Date.UTC(2008, 0, 11, 4, 0, 0);

There is an even easier way tofigure out this GMT stuff. Set your system clock and time zone to thelocal time of where the event is to occur (you may already be there).Then run this little calculator page to determine the GMT date and time:

	<html>
 	<head>
 	<script type="text/javascript">
 	function calcGMT(form) {
 	    var date = new Date(form.year.value, form.month.value, form.day.value,
 	                        form.hour.value, form.minute.value, form.second.value);
 	    form.output.value = date.toUTCString();
 	}
 	</script>
 	</head>
 	<body>
 	<form>
 	Year:<input type="text" name="year" value="0000" />
 
 	Month (0-11):<input type="text" name="month" value="0" />
 
 	Day (1-31):<input type="text" name="day" value="0" />
 
 	Hour (0-23):<input type="text" name="hour" value="0" />
 
 	Minute (0-59):<input type="text" name="minute" value="0" />
 
 	Second (0-59):<input type="text" name="second" value="0" />
 
 	<input type="button" value="Get GMT" onclick="calcGMT(this.form)" />
 
 	<input type="text" name="output" size="60" />
 	</body>
 	</html>



If you change your system clock settings to use this calculator, be sure to change them back to your local time and time zone.Another kind of counter is a short-term counter for applicationslike student quizzes or other controlled environments in which you needsomething to time out or navigate to another page. It's not uncommon insuch cases to display, say, a 60-second counter.

The following code is a modified version of the script in Example 15-5 that displays a <a name="the number">countdown timer for the number of seconds passed as a parameter to the primary function:


	// global variables
 	var targetInMS, timerInterval;
 	var oneSec = 1000;
 
 	// pass the number of seconds to count down
 	function startTimer(secs) {
 	    var targetTime = new Date();
 	    targetTime.setSeconds(targetTime.getSeconds() + secs);
 	    targetInMS = targetTime.getTime();
 	    // display starting image
 	    setImages(secs);
 	    timerInterval = setInterval("countDown()", 100);
 	}
 
 	function countDown() {
 	    var nowInMS = (new Date()).getTime();
 	    var diff = targetInMS - nowInMS;
 	    if (diff <= 0) {
 	        clearInterval(timerInterval);
 	        alert("Time is up!");
 	        // more processing here
 	    } else {
 	        var scratchPad = diff / oneSec;
 	        var secsLeft = Math.floor(scratchPad);
 	        setImages(secsLeft);
 	    }
 	}
 
 	function setImages(secs) {
 	    var i;
 	    secs = formatNum(secs, 2);
 	    for (i = 0; i < secs.length; i++) {
 	        document.images["seconds" + i].src = imgArray[parseInt(secs.charAt(i))].src;
 	    }
 	}
 
 	function formatNum(num, len) {
 	    var numStr = "" + num;
 	    while (numStr.length < len) {
 	        numStr = "0" + numStr;
 	    }
 	    return numStr
 	}
 
 


This code is easily modifiable to extend the timer to minutes and seconds if you like.

Cover of Javascript & DHTML Cookbook
Learn more about this topic from Javascript & DHTML Cookbook, 2nd Edition. 

In today's Web 2.0 world, Javascript and Dynamic HTML are at the center of the hot new approach to designing highly interactive pages on the client side. With this environment in mind, the new edition of this book offers bite-sized solutions to very specific scripting problems that web developers commonly face. Each recipe includes a focused piece of code that you can insert right into your application.

Learn More Read Now on Safari


Tags:
0 Subscribe


0 Replies