Compared to the JavaScript digital clock I demonstrated in the previous article, this SVG analog clock uses fewer lines of code, and has the advantage of being infinitely scalable.

I’ve always admired the elegance of the code, expressed earlier by Felix Gnass. First, there’s my version of the , which consists of just four elements: the dial, and three rectangular hands (hours, minutes, and seconds):

<svg id="clock" viewBox="0 0 100 100">
	<circle id="face" cx="50" cy="50" r="45"/>
	<g id="hands">
		<rect id="hour" x="48.5" y="12.5" width="5" height="40" rx="2.5" ry="2.55" />
		<rect id="min" x="48" y="12.5" width="3" height="40" rx="2" ry="2"/>
		<line id="sec" x1="50" y1="50" x2="50" y2="16" />
	</g>
</svg>

The markup is, I hope, fairly self-explanatory: the <circle> element has a radius of 45 units, with its center 50 units from the top left corner of the SVG element; the hour, min and sec elements are positioned similarly. The hour and minute hands are rectangles 40 units long, and have a border-radius (in SVG, applied as rx and ry).

Rather than trying to style the elements inline, I’ll do that in CSS:

#face {
	stroke-width: 2px; stroke: #fff; 
}
#hour, #min, #sec {
	stroke-width: 1px; fill: #333; stroke: #555;
}
#sec { stroke: #f55; }

At this point, the clock has all hands pointing to 12. The JavaScript, written at the bottom of the page, changes all that:

setInterval(function() {
	function r(el, deg) {
		el.setAttribute('transform', 'rotate('+ deg +' 50 50)')
	}
	var d = new Date()
	r(sec, 6*d.getSeconds())  
	r(min, 6*d.getMinutes())
	r(hour, 30*(d.getHours()%12) + d.getMinutes()/2)
}, 1000)

This differs from the previous script in several significant ways:

First, it uses a setInterval that encompasses the entire script. The function inside runs every second, due to the 1000 passed to setInterval as an argument in milliseconds.

d is a variable based on the Date() object, just like the previous example. For brevity, the script takes advantage of the fact that elements with an id attribute automatically become references in scripts. While this isn’t a recommended practice, it’s certainly doable, making the use of sec, min and hour in the script direct references to the matching SVG elements.

The r function takes two arguments: the element to change, and the amount of rotation. Note that we’re taking about SVG rotation, not CSS, so there’s no need for vendor prefixes.

For sec, r is passed the id of the element, and 6 × the number of seconds in the current time. If it’s 0 seconds, deg will be 0, meaning that the element won’t rotate at all. If it’s 30 seconds, 30 × 6 = 180° of rotation. (The 50 50 value ensures that the element always rotates from the center of the SVG). min takes gets the same treatment, while hour is a little tricker: it uses the remainder of dividing the current hour by 12, multiplied by 30, and adds the number of minutes divided by 2. In other words, if it is 15 minutes past midnight, the calculation becomes:


r(hour, 30 * 0 + (15 / 2))
> 7.5

It if it is 3.45pm (remembering that JavaScript uses 24 hour time by default, so the hour division will be 15 % 12. The calculation is:

r(hour, 30 * 3 + (45 / 2))
> 112.5

All told, it’s a very nice little piece of code, which I hope will find its uses in your projects.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/HLBki