Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kristopherjohnson/1db0d39a9ed54d224ee7 to your computer and use it in GitHub Desktop.
Save kristopherjohnson/1db0d39a9ed54d224ee7 to your computer and use it in GitHub Desktop.
Animated clock implemented using D3.js

I am learning how to use the D3.js library to do data visualizations. It doesn't really make sense to consider hour, minute, and second as data to be "visualized", but this was a simple exercise to learn how to create SVG elements and animate them as the data changes.

To see the clock in action, go to http://bl.ocks.org/kristopherjohnson/1db0d39a9ed54d224ee7

svg.clock {
stroke-linecap: round;
}
.face {
stroke: #aac;
stroke-width: 6;
}
.hourtick.face {
}
.minutetick.face {
stroke-width: 2;
}
.hand {
stroke: #336;
stroke-width: 8;
}
.hour.hand {
stroke-width: 12;
}
.minute.hand {
}
.second.hand {
stroke: red;
stroke-width: 4;
}
var showD3Clock = function() {
var w = 320 // Width of SVG element
var h = 320 // Height of SVG element
var cx = w / 2 // Center x
var cy = h / 2 // Center y
var margin = 4
var r = w / 2 - margin // Radius of clock face
var svg = d3.select("body").append("svg")
.attr("class", "clock")
.attr("width", w)
.attr("height", h)
makeClockFace()
// Create hands from dataset
svg.selectAll("line.hand")
.data(getTimeOfDay())
.enter()
.append("line")
.attr("class", function (d) { return d[0] + " hand"})
.attr("x1", cx)
.attr("y1", function (d) { return cy + handBackLength(d) })
.attr("x2", cx)
.attr("y2", function (d) { return r - handLength(d)})
.attr("transform", rotationTransform)
// Update hand positions once per second
setInterval(updateHands, 1000)
function makeClockFace() {
var hourTickLength = Math.round(r * 0.2)
var minuteTickLength = Math.round(r * 0.075)
for (var i = 0; i < 60; ++i) {
var tickLength, tickClass
if ((i % 5) == 0) {
tickLength = hourTickLength
tickClass = "hourtick"
}
else {
tickLength = minuteTickLength
tickClass = "minutetick"
}
svg.append("line")
.attr("class", tickClass + " face")
.attr("x1", cx)
.attr("y1", margin)
.attr("x2", cx)
.attr("y2", margin + tickLength)
.attr("transform", "rotate(" + i * 6 + "," + cx + "," + cy + ")")
}
}
function getTimeOfDay() {
var now = new Date()
var hr = now.getHours()
var min = now.getMinutes()
var sec = now.getSeconds()
return [
[ "hour", hr + (min / 60) + (sec / 3600) ],
[ "minute", min + (sec / 60) ],
[ "second", sec ]
]
}
function handLength(d) {
if (d[0] == "hour")
return Math.round(0.45 * r)
else
return Math.round(0.90 * r)
}
function handBackLength(d) {
if (d[0] == "second")
return Math.round(0.25 * r)
else
return Math.round(0.10 * r)
}
function rotationTransform(d) {
var angle
if (d[0] == "hour")
angle = (d[1] % 12) * 30
else
angle = d[1] * 6
return "rotate(" + angle + "," + cx + "," + cy + ")"
}
function updateHands() {
svg.selectAll("line.hand")
.data(getTimeOfDay())
.transition().ease("bounce")
.attr("transform", rotationTransform)
}
}
showD3Clock()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Clock</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<link href="d3clock.css" rel="stylesheet">
</head>
<body>
<script src="d3clock.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment