A swiss railway clock in D3.js

Screen Shot 2015-06-05 at 5.26.54 PM

 

The other day I saw this cool JavaScript+CSS clock and I immediately thought that I wanted to create an analog clock in D3.js. First of all as an exercise, but also with the aim —perhaps— of smuggling it in to a future dashboard 😉

It seemed straightforward: just paint the clock and re-paint it each second. Right? Well, yes if you’re lazy. The better way is to paint the clock and periodically rotate the hands.

As with most things on the internet, turns out I was late to the party. Some much more clever people have built D3 clocks and even a multi-clock D3 visualization for displaying multiple time zones.

Good. I had some ideas and a starting point.


I’m in love with the Swiss Federal Railways (SBB) clock, designed by Hans Hilfiker. It’s an emblem of the most effective train system in the world, and a testimony of exquisite swiss modernism. I wanted to make that.

There’s already an SVG visualization of the SBB clock (here’s the code). As I was checking it out, it made me realize for the first time that the axis of rotation is not at the end of the hands, but like at 10% of its length. And that extra length is different for the seconds hand. Also, that ball at the end of the seconds hand was going to be tricky.

As with all great designs of that era, everything is proportional in that clock. I noticed that I would be able to derive all the measurements from the width of the minute ticks. So I defined a starting measurement unit and multiplied away!

The key for doing the hands rotation in D3 is to enclose each hand in its own g element and rotate those g elements using setInterval. The rotation of the hands in the SBB clock is smooth, and thankfully D3 offers transitions for seamless interpolations.

The seconds and minutes hands have to rotate 6˚ each time (360˚÷60) and the hours hand has to rotate 30˚. Since the clock shows only 12 hours, you have to multiply 30˚ by the modulo 12 of the hours.

   
clockHand.transition().duration(1000).ease('linear').attr('transform', function(d,i) {
	if (d.unit==='hours'){
		return 'rotate('+d.numeric%12 * 30+')';
	} else {
		return 'rotate('+d.numeric * 6+')';
	}
});

I was able to quickly put together a very rudimentary version and tweak the design little by little. Then I decided not to waste my first tests, got a little bit carried away and externalized all the functions that defined the characteristics of the clock. I ended up with a module that enables you to create multiple instances of the clock, each with its own configuration, defined in the ‘face’ variable of the configuration object.

d3clock({
	target:'#sbb',
	face:'sbb',
	width:500,
	//date:'Mon May 25 2015 10:09:37',
	TZOffset:{
		hours:0
	}
});



You can get the code for the library here.

Mind you, this implementation has its differences with the SBB clock (perhaps that will spare me from a takedown notice?):

  • The SBB clock makes a 2 second pause at the end of each rotation. Yes, crazy, look.
  • The hands in the original clock are not rectangles, but very tall truncated triangles.

I'm a software architect and I help people solve their problems with technology. In this site, I write about how to seize the opportunities that a hyperconnected world offers us. How to live simpler and more productive lives. I invite you to check the "Best of" section. If you want to contact me, or work with me, you can use the social links below.

TAGS: