|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<html> |
|
<head> |
|
<title>DST Transitions</title> |
|
<style> |
|
|
|
body { |
|
background: #fff; |
|
} |
|
|
|
svg{ |
|
stroke: #000; |
|
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; |
|
} |
|
|
|
h1 { |
|
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; |
|
font-weight: 200; |
|
font-size: 24px; |
|
} |
|
|
|
div.clocks { |
|
height: 215px; |
|
} |
|
|
|
#rim { |
|
fill: none; |
|
stroke: #999; |
|
stroke-width: 1.5px; |
|
} |
|
|
|
.minute-hand{ |
|
stroke-width:2; |
|
stroke-linecap:round; |
|
} |
|
|
|
.hour-hand{ |
|
stroke-width:3; |
|
stroke-linecap:round; |
|
} |
|
|
|
.hands-cover{ |
|
stroke-width:.75; |
|
fill:#fff; |
|
} |
|
|
|
.minute-tick{ |
|
stroke-width:.75; |
|
fill:#000; |
|
} |
|
|
|
.hour-tick{ |
|
stroke-width:2; //same as the minute hand |
|
} |
|
|
|
.minute-label{ |
|
font-size: 14px; |
|
stroke: #666; |
|
} |
|
|
|
.hour-label{ |
|
font-size: 24px; |
|
} |
|
|
|
|
|
</style> |
|
</head> |
|
<body> |
|
<h1>Europe (Synchronised)</h1> |
|
<div id="europe" class="clocks"></div> |
|
<h1>USA (Local)</h1> |
|
<div id="usa" class="clocks"></div> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script> |
|
|
|
var radians = 0.0174532925, |
|
clockRadius = 100, |
|
margin = 5, |
|
width = (clockRadius+margin)*2, |
|
height = (clockRadius+margin)*4+150, |
|
hourHandLength = 2*clockRadius/3, |
|
minuteHandLength = clockRadius, |
|
minuteTickStart = clockRadius; |
|
minuteTickLength = -10, |
|
hourTickStart = clockRadius, |
|
hourTickLength = -18 |
|
minuteLabelRadius = clockRadius - 40; |
|
minuteLabelYOffset = 5 |
|
hourLabelRadius = clockRadius - 40 |
|
hourLabelYOffset = 7; |
|
|
|
|
|
var hourScale = d3.scale.linear() |
|
.range([0,330]) |
|
.domain([0,11]); |
|
|
|
var minuteScale = d3.scale.linear() |
|
.range([0,354]) |
|
.domain([0,59]); |
|
|
|
var london = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:0 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 2, |
|
'changed': false, |
|
'name': 'London', |
|
'id': 'lhr', |
|
'where': 'europe' |
|
}; |
|
|
|
var berlin = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:1 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 3, |
|
'changed': false, |
|
'name': 'Berlin', |
|
'id': 'txl', |
|
'where': 'europe' |
|
}; |
|
|
|
var helsinki = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:2 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 4, |
|
'changed': false, |
|
'name': 'Helsinki', |
|
'id': 'hel', |
|
'where': 'europe' |
|
}; |
|
|
|
// note that these are correct relative to each other but not to Europe |
|
// I didn't think waiting for four clock rotations was a good idea |
|
|
|
var la = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:8 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 2, |
|
'changed': false, |
|
'name': 'Los Angeles', |
|
'id': 'lax', |
|
'where': 'usa' |
|
}; |
|
|
|
var denver = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:9 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 2, |
|
'changed': false, |
|
'name': 'Denver', |
|
'id': 'den', |
|
'where': 'usa' |
|
}; |
|
|
|
var chicago = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:10 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 2, |
|
'changed': false, |
|
'name': 'Chicago', |
|
'id': 'ord', |
|
'where': 'usa' |
|
}; |
|
|
|
var nyc = { |
|
'handData': [ |
|
{ type:'hour', length:-hourHandLength, scale:hourScale, value:11 }, |
|
{ type:'minute', value:0, length:-minuteHandLength, scale:minuteScale } |
|
], |
|
'dst': 2, |
|
'changed': false, |
|
'name': 'New York', |
|
'id': 'jfk', |
|
'where': 'usa' |
|
}; |
|
|
|
clocks = [london, berlin, helsinki, la, denver, chicago, nyc]; |
|
|
|
function drawClock(clock){ //create all the clock elements |
|
var svg = d3.select("div#"+clock['where']).append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var face = svg.append('g') |
|
.attr('id','clock-face-'+clock['id']) |
|
.attr('transform','translate(' + (clockRadius + margin) + ',' + (clockRadius + margin) + ')'); |
|
|
|
//add marks for minutes |
|
face.selectAll('.minute-tick') |
|
.data(d3.range(0,60)).enter() |
|
.append('line') |
|
.attr('class', 'minute-tick') |
|
.attr('x1',0) |
|
.attr('x2',0) |
|
.attr('y1',minuteTickStart) |
|
.attr('y2',minuteTickStart + minuteTickLength) |
|
.attr('transform',function(d){ |
|
return 'rotate(' + minuteScale(d) + ')'; |
|
}); |
|
|
|
face.selectAll('.minute-label') |
|
.data(d3.range(5,61,5)) |
|
.enter() |
|
.append('text') |
|
.attr('class', 'minute-label') |
|
.attr('text-anchor','middle') |
|
.attr('x',function(d){ |
|
return minuteLabelRadius*Math.sin(minuteScale(d)*radians); |
|
}) |
|
.attr('y',function(d){ |
|
return -minuteLabelRadius*Math.cos(minuteScale(d)*radians) + minuteLabelYOffset; |
|
}) |
|
.text(function(d){ |
|
if (d==30) { |
|
return clock['name']; |
|
} |
|
return ''; |
|
}); |
|
|
|
//... and hours |
|
face.selectAll('.hour-tick') |
|
.data(d3.range(0,12)).enter() |
|
.append('line') |
|
.attr('class', 'hour-tick') |
|
.attr('x1',0) |
|
.attr('x2',0) |
|
.attr('y1',hourTickStart) |
|
.attr('y2',hourTickStart + hourTickLength) |
|
.attr('transform',function(d){ |
|
return 'rotate(' + hourScale(d) + ')'; |
|
}); |
|
|
|
|
|
var hands = face.append('g').attr('id','clock-hands-'+clock['id']); |
|
|
|
face.append('g').attr('id','face-overlay') |
|
.append('circle').attr('class','hands-cover') |
|
.attr('x',0) |
|
.attr('y',0) |
|
.attr('r',clockRadius/20); |
|
|
|
hands.selectAll('line') |
|
.data(clock['handData']) |
|
.enter() |
|
.append('line') |
|
.attr('class', function(d){ |
|
return d.type + '-hand'; |
|
}) |
|
.attr('x1',0) |
|
.attr('y1',function(d){ |
|
return d.balance ? d.balance : 0; |
|
}) |
|
.attr('x2',0) |
|
.attr('y2',function(d){ |
|
return d.length; |
|
}) |
|
.attr('transform',function(d){ |
|
return 'rotate('+ d.scale(d.value) +')'; |
|
}); |
|
} |
|
|
|
function moveHands(clock){ |
|
d3.select('#clock-hands-'+clock['id']).selectAll('line') |
|
.data(clock['handData']) |
|
.transition() |
|
.ease('linear') |
|
.attr('transform',function(d){ |
|
return 'rotate('+ d.scale(d.value) +')'; |
|
}); |
|
} |
|
|
|
function updateData(clock){ |
|
var inc = 75; |
|
clock['handData'][0].value += inc/3600; |
|
clock['handData'][1].value += inc/60; |
|
|
|
if (clock['dst']-1 < clock['handData'][0].value && |
|
clock['handData'][0].value < clock['dst'] && |
|
!clock['changed']) { |
|
|
|
d3.select('#clock-face-'+clock['id']).style('stroke', '#f00') |
|
} |
|
|
|
|
|
if (clock['dst'] < clock['handData'][0].value && |
|
clock['handData'][0].value < clock['dst']+1 && |
|
!clock['changed']) { |
|
|
|
clock['handData'][0].value = clock['dst']-1; |
|
clock['changed'] = true; |
|
d3.select('#clock-face-'+clock['id']).style('stroke', '#000') |
|
} |
|
|
|
if (12 < clock['handData'][0].value) { |
|
clock['handData'][0].value -= 12; |
|
clock['changed'] = false; |
|
} |
|
} |
|
|
|
for (var i = 0; i < clocks.length; i++) { |
|
drawClock(clocks[i]); |
|
} |
|
|
|
setInterval(function(){ |
|
for (var i = 0; i < clocks.length; i++) { |
|
updateData(clocks[i]); |
|
moveHands(clocks[i]); |
|
}; |
|
}, 100); |
|
|
|
d3.select(self.frameElement).style("height", height + "px"); |
|
</script> |
|
</body> |
|
</html> |