Apple-Style Counter

February 12th, 2010 / Code

When I saw the 10 billion song counter on Apple’s website yesterday, I immediately right-clicked on it to see if it was flash. No big surprise to see that it wasn’t, this being Apple, and when I saw it was done using JavaScript I knew how I’d be wasting the next few hours.

Counter from apple.com

Apple’s 10 billion song countdown.

My first instinct was to use Chrome’s developer tools to inspect the page and check out the JavaScript for the counter to get some clues as to how to go about re-creating it. After a few seconds of looking at Apple’s minified code, I knew I’d get no help there. After grabbing the digits and comma graphic they used, I set out to avoid the work I was supposed to be doing to create a counter from scratch using these two images and jQuery.

Here it is

I’ll give a brief overview of the steps taken to reproduce the counter, but for those that want to cut to the chase, here it is. The code is commented enough so that anyone interested can view the source and see what’s going on.

Note: This counter did not actually track the number of iTunes downloads, but is an example of how to create a similar counter for your own purposes.

Be sure to read all the way down for more demos.

Basics

Looking at the image closely, we can see that each frame is 103px in height, with five frames of animation between digits, leaving 618px of space between each digit. So, digit zero would have a background position of '0 0', one would be '0 -608px', two would be '0 -1236px', etc. My plan was to use an unordered list to hold the digits and use jQuery to animate the background position of each list item.

<ul>
  <li id="d9"></li>
  <li class="seperator"></li>
  <li id="d8"></li>
  <li id="d7"></li>
  <li id="d6"></li>
  <li class="seperator"></li>
  <li id="d5"></li>
  <li id="d4"></li>
  <li id="d3"></li>
  <li class="seperator"></li>
  <li id="d2"></li>
  <li id="d1"></li>
  <li id="d0"></li>
</ul>

And the CSS:

*{
  margin:0;
  padding:0;
}
ul{
  list-style-type:none;
  width:566px;
  margin:50px auto;
}
li{
  float:left;
  background:url(filmstrip.png) 0 0 no-repeat;
  width:53px;
  height:103px;
}
li.seperator{
  background:url(comma.png) 2px 75px no-repeat;
  width:12px;
}

That’s it for HTML and CSS, the rest is JavaScript.

Making it work

It took no time to get a simple counter running, but the hairy part was triggering a five-frame animation for each digit that needed to change. Because I wanted to mimic the functionality of the counter on Apple’s site, it needed to look like it was counting at a very fast increment, with variable animation speeds depending on the digit.

After incrementing the value, the first step is to see which digits need to be animated:

function digitCheck(x,y){
  var digitsOld = splitToArray(x),
  digitsNew = splitToArray(y);
  for (var i = 0, c = digitsNew.length; i < c; i++){
    if (digitsNew[i] != digitsOld[i]){
      animateDigit(i, digitsOld[i], digitsNew[i]);
    }
  }
}

This takes inputs x (pre-increment value) and y (post-increment value), and sends them to a helper function I wrote called splitToArray, which breaks each value into an array of individual digits. It then compares each digit, and if there is a change, passes the info on to animateDigit.

Inside animateDigit, the most difficult part was getting the animations for each digit cued up correctly. Inside the loop that controls the animation, I needed to slide the background position down five times with a specific delay, and my first solution was using setTimeout, and the statement:

setTimeout(doAnimate, timeOut, n, pos);

This worked great in Chrome and FF, and I thought I was done... until I checked it in IE. I had forgotten you can't pass parameters to functions with setTimeout in this way, so you need to use a closure:

setTimeout(function(){doAnimate(n,pos)}, timeOut);

Simple enough, I thought, but that made the animation choke up in every browser. No good.

I slept on it, then this morning thought about using jQuery's new delay method added in version 1.4. Boom! I was able to do away with the doAnimate function all together, and kill it all with one pass:

$('#d' + n).delay(speed).animate({'background-position': '0 ' + pos + 'px'}, 0);

I now had cross-browser harmony, and had once again spent time away from paying projects to build something I have absolutely no use for :)

Customizing

When making this demo, I chose to use the same Apple graphics so when it was finished, I could look at the two side-by-side and see if I got the functionality correct. This post is just me sharing my learning process with you, so if in the future you ever have the need for a count down/up graphic, maybe this will help. The impression shouldn't be "how to rip-off Apple's look", but rather "how to have the same functionality in my own projects."

Customizing this to your own graphics is very easy. All you need is a consistent spacing between your animation frames, and be able to add. Most of the customization happens at the beginning of the JavaScript:

// Array to hold each digit's starting background-position Y value
var initialPos = [0, -480, -960, -1440, -1920, -2400, -2880, -3360, -3840, -4320];
// Amination frames
var animationFrames = 5;
// Frame shift
var frameShift = 80;

The initialPos array holds the starting Y value of each digit, in increments of 480 (80px per frame x 6 frames per digit). animationFrames says there are 5 animation frames between digits, and frameShift is the frame height. Those are the only changes needed to make it function properly (besides updating the CSS), and further animation tweaking can be done in the function animateDigit.

Update 1

Here is another example demonstrating how to make a clock using the same animation technique.

Update 2

My original demo was based on counting to 10 billion, so had a strict number of digits. I realize that is not the most practical application, so I made a dynamic counter example where the JavaScript takes care of HTML for each digit, as well as commas when necessary. You can set whatever number you want via the URL query string (set n = number), or view the page by itself to just generate a random number. View the source to see different ways of setting a start number for the counter to use.

Update 3

Example with zero-filled numbers.

Update 4

As per many requests, and the help of a visitor who made three new digit graphics, I have yet another example of this animation technique in action. This time it is not counting up, but rather down—to any date in the future, in 'days : hours : minutes : seconds' format. It handles all HTML and formatting itself, all you need to do is plug in a date. View countdown demo.

Warning: Don't use the countdown script in a live site, because the jQuery animation technique used will not work properly in Chrome, see bug here.

It uses the @font-face font kit BD Cartoon Shout from Font Squirrel. As usual, code is commented if you're curious. Here is everything for the countdown in a zip file.

Update: November 15, 2010

I've rewritten entire script and added lots of new functionality. View revisited counter.

Update: February 7, 2011

This script will not work properly with jQuery 1.5, and will no longer be maintained. Think of this post as a first draft of me trying to get the animation working; the code is outdated. If you want to use this type of counter please use the newer version of the script.