Skip to content

Instantly share code, notes, and snippets.

@vasturiano
Last active April 20, 2017 19:20
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 vasturiano/118e167e9bc93356221f67905c87cd6f to your computer and use it in GitHub Desktop.
Save vasturiano/118e167e9bc93356221f67905c87cd6f to your computer and use it in GitHub Desktop.
Analog Clock
license: mit

An analog clock, using the D3 radial axis to render the frame.

<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.23.1/babel.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.min.js"></script>
<script src="//unpkg.com/d3-radial-axis@1.5/dist/d3-radial-axis.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg id="canvas"></svg>
<script type="text/babel" src="index.js"></script>
</body>
const r = Math.min(window.innerWidth, window.innerHeight) / 2,
secMinScale = d3.scaleLinear().domain([0, 60]).range([0, 360]),
hourScale = d3.scaleLinear().domain([0, 12]).range([0, 360])
const pointersRelDimensions = [
{ class: 'hour', width: 0.05, height: 0.55 },
{ class: 'min', width: 0.05, height: 0.85 },
{ class: 'sec', width: 0.02, height: 0.85 }
]
// Size canvas
const svg = d3.select('#canvas')
.attr('width', r * 2)
.attr('height', r * 2)
.attr('viewBox', `${-r} ${-r} ${r*2} ${r*2}`)
// Add background
svg.append('circle').classed('background', true)
.attr('cx', 0)
.attr('cy', 0)
.attr('r', r)
// Add axis
svg.append('g').classed('axis', true)
.call(d3.axisRadialInner(
hourScale.copy().range([0, 2 * Math.PI]),
r - 1
)
.ticks(12)
.tickSize(12)
)
svg.append('g').classed('minor-ticks', true)
.call(d3.axisRadialInner(
secMinScale.copy().range([0, 2 * Math.PI]),
r - 1
)
.ticks(60)
.tickSize(6)
)
// Add pointers
svg.append('g').classed('pointers', true)
.attr('transform', `scale(${r})`)
.selectAll('rect')
.data(pointersRelDimensions)
.enter()
.append('rect')
.attr('class', d=> d.class)
.attr('x', d => -d.width/2)
.attr('y', d => -d.height + d.width/2)
.attr('width', d => d.width)
.attr('height', d => d.height)
.attr('rx', 0.02)
.attr('ry', 0.03)
// Add center
svg.select('.pointers')
.append('circle').classed('center', true)
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 0.02)
// Kick-off clock
framed()
function framed() {
const dt = new Date()
const ms = dt.getMilliseconds(),
secs = dt.getSeconds() + ms/1000,
mins = dt.getMinutes() + secs/60,
hours = dt.getHours()%12 + mins/60
d3.select('.pointers .hour').attr('transform', `rotate(${hourScale(hours)})`)
d3.select('.pointers .min').attr('transform', `rotate(${secMinScale(mins)})`)
d3.select('.pointers .sec').attr('transform', `rotate(${secMinScale(secs)})`)
requestAnimationFrame(framed)
}
body {
text-align: center;
font-family: Sans-serif;
margin: 0;
}
.background {
stroke-width: 0;
fill: Lavender;
fill-opacity: 0.3;
}
.axis .domain, .axis .tick line {
stroke-width: 2px;
stroke: DarkSlateGrey;
}
.axis .tick:first-of-type {
display: none; // hide 0 tick
}
.axis .tick text {
font-size: 16px;
}
.minor-ticks text, .minor-ticks path {
display: none; // Hide all but ticks
}
.pointers rect {
fill-opacity: 0.7;
}
.pointers .hour, .pointers .min {
fill: green;
}
.pointers .sec {
fill: red;
}
.pointers .center {
fill: darkgrey;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment