Last active
June 1, 2016 13:19
-
-
Save martinVelicky/15d8c222750d333eab42bbbd0717c7d9 to your computer and use it in GitHub Desktop.
Circular clock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.idea/ | |
config.codekit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Circular Clock</title> | |
<script src="//d3js.org/d3.v4.0.0-alpha.44.min.js"></script> | |
<style> | |
body { | |
text-align: center; | |
} | |
svg text { | |
font-size: 14px; | |
} | |
svg path { | |
stroke-width: 3px; | |
stroke: #fff; | |
} | |
#indicator { | |
fill: none; | |
stroke: black; | |
stroke-width: 4px; | |
} | |
</style> | |
<body> | |
<svg width="520" height="520"></svg> | |
<script type="text/javascript"> | |
function textAngle(angle) { | |
return angle - 90; | |
} | |
function angle(d, offset) { | |
return (d.startAngle + d.endAngle) * 90 / Math.PI + offset; | |
} | |
var svg = d3.select("svg"), | |
width = +svg.attr("width"), | |
height = +svg.attr("height"), | |
radius = 280, | |
pi = Math.PI, | |
duration = 750; | |
var fields = [ | |
{r1: 0.2 * radius, r2: 0.35 * radius, interval: d3.timeWeek, subinterval: d3.timeDay, format: d3.timeFormat("%a"), color: "#98DF8A" }, | |
{r1: 0.35 * radius, r2: 0.45 * radius, interval: d3.timeMonth, subinterval: d3.timeDay, format: d3.timeFormat("%d"), color: "#FFBB78" }, | |
{r1: 0.45 * radius, r2: 0.6 * radius, interval: d3.timeYear, subinterval: d3.timeMonth, format: d3.timeFormat("%b"), color: "#C5B0D5" }, | |
{r1: 0.6 * radius, r2: 0.7 * radius, interval: d3.timeDay, subinterval: d3.timeHour, format: d3.timeFormat("%H"), color: "#cdddf2" }, | |
{r1: 0.7 * radius, r2: 0.8 * radius, interval: d3.timeHour, subinterval: d3.timeMinute, format: d3.timeFormat("%M"), color: "#cdddf2" }, | |
{r1: 0.8 * radius, r2: 0.9 * radius, interval: d3.timeMinute, subinterval: d3.timeSecond, format: d3.timeFormat("%S"), color: "#cdddf2" } | |
]; | |
var pie = d3.pie().startAngle(pi / 2).endAngle(2 * pi + pi / 2).value(function() { | |
return 1; | |
}).sort(null); | |
var svgBody = svg.append("g") | |
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); | |
var groups = svgBody.selectAll("g") | |
.data(fields) | |
.enter() | |
.append("g") | |
.attr("class", "field"); | |
var fieldTicks = groups.selectAll(".field-tick").data(function(d) { | |
d.dateStart = d.interval.floor(new Date()); | |
d.range = d.subinterval.range(d.dateStart, d.interval.offset(d.dateStart, 1)); | |
d.arc = d3.arc().innerRadius(d.r1).outerRadius(d.r2); | |
d.slices = pie(d.range); | |
return d.range.map(function(x) { | |
return { | |
date: x, | |
field: d | |
}; | |
}); | |
}).enter().append("g").attr("class", "field-tick"); | |
fieldTicks.append("path").attr("d", function(d, i) { | |
var field = this.parentNode.__data__.field; | |
return field.arc(field.slices[i]); | |
}).attr("fill", function() { | |
var field = this.parentNode.__data__.field; | |
return field.color; | |
}); | |
fieldTicks.append("text") | |
.text(function(d) { | |
return d.field.format(d.date); | |
}) | |
.attr("dy", ".35em") | |
.attr("text-anchor", "middle") | |
.attr("transform", function(d, i) { | |
var field = this.parentNode.__data__.field; | |
var slices = field.slices; | |
var coords = field.arc.centroid(slices[i]); | |
return "translate(" + coords + ")rotate(" + angle(slices[i], -90) + ")"; | |
}); | |
svg.append("rect") | |
.attr("id", "indicator") | |
.attr("width", radius * 0.7) | |
.attr("fill", "red") | |
.attr("height", 26) | |
.attr("x", width / 2 + radius * 0.2).attr("y", height / 2 - 13); | |
(function tick() { | |
var now = new Date, | |
then = new Date(+now + duration), | |
next = d3.timeSecond.offset(d3.timeSecond(then), 1), | |
delay = next - duration - now; | |
// Skip ahead a second if there’s not time for this transition. | |
if (delay < duration) { | |
delay += 1000; | |
then = next; | |
} | |
groups.transition().duration(duration) | |
.each(function(d, i) { | |
var index = d.subinterval.count(d.dateStart, then); | |
var offset = (d.slices[i].endAngle - d.slices[i].startAngle) / 2; | |
d.angle = - (2 * pi / d.range.length) * index - offset; | |
}).attr("transform", function(d) { | |
return "rotate(" + d.angle / pi * 180 + ")"; | |
}); | |
setTimeout(tick, delay); | |
})(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment