CSS sure can turn into a lot of pixel tweaking if you let it. I called it quits when the need to tweak the horizontal spacing of the hour numerals from 10 to 2 became apparent.
Last active
March 1, 2016 15:25
-
-
Save jcdcodes/35b102254d8802a19644 to your computer and use it in GitHub Desktop.
Braunish Travel Alarm
This file contains 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> | |
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script> | |
<style type="text/css"> | |
.border { | |
fill: #f8f8f8; | |
stroke: #aaa; | |
stroke-width: 1px; | |
} | |
.second { | |
fill: none; | |
stroke: #fd4; | |
stroke-width: 3.8px; | |
} | |
.hand { | |
stroke-linejoin: round; | |
stroke-linecap: round; | |
} | |
.hour { | |
stroke: white; | |
stroke-width: 16px; | |
} | |
.minute { | |
stroke: white; | |
stroke-width: 8.0px; | |
} | |
.hub { | |
stroke: none; | |
stroke-width: 4.2px; | |
fill: #fd4; | |
} | |
.bezel { | |
stroke: #444; | |
stroke-width: 10.5px; | |
fill: #111; | |
} | |
.hourlabels { | |
font-family: Helvetica, Arial, sans-serif; | |
font-weight: Light; | |
font-size: 26pt; | |
letter-spacing: -0.1em; | |
fill: #ccc; | |
} | |
.quartz { | |
font-family: Helvetica, Arial, sans-serif; | |
font-size: 10pt; | |
fill: #ddd; | |
} | |
.majortick { | |
stroke: white; | |
stroke-width: 2.5px; | |
} | |
.minortick { | |
stroke: white; | |
stroke-width: 1.5px; | |
} | |
</style> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
var w = 960, | |
h = 500, | |
x = d3.scale.ordinal().domain(d3.range(3)).rangePoints([0, w], 2); | |
var fields = [ | |
{name: "hour", value: 0, size: 12, handlength: 167}, | |
{name: "minute", value: 0, size: 60, handlength: 196}, | |
{name: "second", value: 0, size: 60, handlength: 198} | |
]; | |
var handclasses = ["hour hand", "minute hand", "second hand"]; | |
function angle(d) { | |
return (d.value / d.size) * 2 * Math.PI; | |
} | |
function clockAngle(d) { | |
return -Math.PI/2 + angle(d); | |
} | |
var hand = d3.svg.arc() | |
.innerRadius(10) | |
.outerRadius(function(d,i) { return d.handlength; }) | |
.startAngle(angle) | |
.endAngle(angle); | |
var svg = d3.select("body").append("svg:svg") | |
.attr("width", w) | |
.attr("height", h) | |
.append("svg:g"); | |
// | |
// Border, dial, numerals, and hub. All fixed elements. | |
// | |
svg.append("rect").attr("height", h).attr("width", w).attr("class", "border"); | |
var bezelradius = 230; | |
svg.append("rect") | |
.attr("class", "bezel") | |
.attr("x", w/2 - bezelradius) | |
.attr("y", h/2 - bezelradius) | |
.attr("width", 2 * bezelradius) | |
.attr("height", 2 * bezelradius) | |
.attr("rx", 30) | |
.attr("ry", 30) | |
; | |
svg.append("circle") | |
.attr("class", "bezel") | |
.attr("cx", w/2) | |
.attr("cy", h/2) | |
.attr("r", 210); | |
svg.selectAll("text") | |
//.data(["XII", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI"]) | |
//.data(["12", "", "", "3", "", "", "6", "", "", "9", "", ""]) | |
.data(["12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"]) | |
.enter().append("text") | |
.text(function(d) { return d; }) | |
.attr("class", "hourlabels") | |
.attr("x", function(d, i) { return 170 * Math.cos(clockAngle({value: i, size: 12})); }) | |
.attr("y", function(d, i) { return 167 * Math.sin(clockAngle({value: i, size: 12})); }) | |
.attr("dy", 13) | |
.attr("text-anchor", "middle") | |
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); | |
svg.selectAll("line.majortick") | |
.data(d3.range(12)) | |
.enter().append("line") | |
.attr("x1", function(d, i) { return 187 * Math.cos(clockAngle({value: i, size: 12})); }) | |
.attr("x2", function(d, i) { return 200 * Math.cos(clockAngle({value: i, size: 12})); }) | |
.attr("y1", function(d, i) { return 187 * Math.sin(clockAngle({value: i, size: 12})); }) | |
.attr("y2", function(d, i) { return 200 * Math.sin(clockAngle({value: i, size: 12})); }) | |
.attr("class", "majortick") | |
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); | |
svg.selectAll("line.minortick") | |
.data(d3.range(60)) | |
.enter().append("line") | |
.attr("x1", function(d, i) { return 193 * Math.cos(clockAngle({value: i, size: 60})); }) | |
.attr("x2", function(d, i) { return 200 * Math.cos(clockAngle({value: i, size: 60})); }) | |
.attr("y1", function(d, i) { return 193 * Math.sin(clockAngle({value: i, size: 60})); }) | |
.attr("y2", function(d, i) { return 200 * Math.sin(clockAngle({value: i, size: 60})); }) | |
.attr("class", "minortick") | |
.attr("transform", "translate(" + (w/2) + "," + (h/2) + ")"); | |
svg.append("text") | |
.text("quartz") | |
.attr("class", "quartz") | |
.attr("text-anchor", "middle") | |
.attr("transform", "translate(" + (w/2) + "," + (h/2 - 67) + ")"); | |
setInterval(function() { | |
var now = new Date(); | |
fields[2].previous = fields[2].value; fields[2].value = now.getSeconds(); | |
fields[1].previous = fields[1].value; fields[1].value = now.getMinutes() + (fields[2].value / 60); | |
fields[0].previous = fields[0].value; fields[0].value = now.getHours() % 12 + (fields[1].value / 60); | |
// Smoothly animate hands between x:59 and x+1:00 | |
if (fields[2].value == 0 && fields[2].previous >= 59) fields[2].previous = -1; | |
if (fields[1].value == 0 && fields[1].previous >= 59) fields[1].previous = -1; | |
// Here, we filter not for entries where d.value evaluates to true, but where | |
// there is a number. Otherwise we don't get to see all three hands when | |
// it's midnight, noon, or the top of the hour; zero evaluates to false in javascript. | |
var line = svg.selectAll("path.hand") | |
.data(fields.filter(function(d) { return d.value > -1; }), function(d) { return d.name; }); | |
line.enter().append("svg:path") | |
.attr("transform", function(d) { return "translate(" + (w/2) + "," + (h/2) + ")"; }) | |
.attr("class", function(d, i) { return handclasses[i]; }) | |
; | |
line.transition() | |
.ease("bounce") | |
.duration(200) | |
.attrTween("d", tweenWith(hand)) | |
; | |
svg.append("circle") | |
.attr("class", "hub") | |
.attr("cx", w/2) | |
.attr("cy", h/2) | |
.attr("r", 25); | |
}, 1000); | |
function tweenWith(f) { | |
return function arcTween(b) { | |
var i = d3.interpolate({value: b.previous}, b); | |
return function(t) { | |
return f(i(t)); | |
}; | |
}; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment