Animated D3 Clock in Torque
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
//based on awesome block by Tom Pearson: http://bl.ocks.org/tomgp/6475678 | |
//receives div id and height/width integer | |
function Clock(div,height) { | |
var radians = 0.0174532925, | |
clockRadius = height/2, | |
margin = 50, | |
width = (clockRadius+margin)*2, | |
height = (clockRadius+margin)*2, | |
hourHandLength = 2*clockRadius/3, | |
minuteHandLength = clockRadius, | |
secondHandLength = clockRadius-12, | |
secondHandBalance = 30, | |
secondTickStart = clockRadius; | |
secondTickLength = -10, | |
hourTickStart = clockRadius, | |
hourTickLength = -18 | |
secondLabelRadius = clockRadius + 16; | |
secondLabelYOffset = 5 | |
hourLabelRadius = clockRadius - 40 | |
hourLabelYOffset = 7; | |
var hourScale = d3.scale.linear() | |
.range([0,330]) | |
.domain([0,11]); | |
var minuteScale = secondScale = d3.scale.linear() | |
.range([0,354]) | |
.domain([0,59]); | |
var handData = [ | |
{ | |
type:'hour', | |
value:0, | |
length:-hourHandLength, | |
scale:hourScale | |
}, | |
{ | |
type:'minute', | |
value:0, | |
length:-minuteHandLength, | |
scale:minuteScale | |
} | |
// , | |
// { | |
// type:'second', | |
// value:0, | |
// length:-secondHandLength, | |
// scale:secondScale, | |
// balance:secondHandBalance | |
// } | |
]; | |
this.draw = function() { //create all the clock elements | |
this.updateData(new Date()); //draw them in the correct starting position | |
var svg = d3.select("#" + div).append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var face = svg.append('g') | |
.attr('id','clock-face') | |
.attr('transform','translate(' + (clockRadius + margin) + ',' + (clockRadius + margin) + ')'); | |
//... 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) + ')'; | |
}); | |
// face.selectAll('.hour-label') | |
// .data(d3.range(3,13,3)) | |
// .enter() | |
// .append('text') | |
// .attr('class', 'hour-label') | |
// .attr('text-anchor','middle') | |
// .attr('x',function(d){ | |
// return hourLabelRadius*Math.sin(hourScale(d)*radians); | |
// }) | |
// .attr('y',function(d){ | |
// return -hourLabelRadius*Math.cos(hourScale(d)*radians) + hourLabelYOffset; | |
// }) | |
// .text(function(d){ | |
// return d; | |
// }); | |
var hands = face.append('g').attr('id','clock-hands'); | |
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(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(){ | |
d3.select('#clock-hands').selectAll('line') | |
.data(handData) | |
// .transition() | |
// .duration(500) | |
.attr('transform',function(d){ | |
return 'rotate('+ d.scale(d.value) +')'; | |
}); | |
} | |
this.updateData = function(t){ | |
//var t = new Date(); | |
handData[0].value = (t.getUTCHours() % 12) + t.getMinutes()/60 ; | |
handData[1].value = t.getMinutes(); | |
//handData[2].value = t.getSeconds(); | |
moveHands(); | |
} | |
//drawClock(); | |
//d3.select(self.frameElement).style("height", height + "px"); | |
} |
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 lang="en"> | |
<head profile="http://www.w3.org/2005/10/profile"> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> | |
<meta name="description" content=""> | |
<meta name="author" content=""> | |
<link rel="icon" href="./favicon.ico"> | |
<title>Torque D3 Clock</title> | |
<link rel="stylesheet" href="https://cartodb-libs.global.ssl.fastly.net/cartodb.js/v3/themes/css/cartodb.css" /> | |
<link rel="icon" type="image/png" href="./favicon.png"> | |
</head> | |
<style> | |
html, body, #container { | |
height: 100%; | |
width: 100%; | |
overflow: hidden; | |
margin:0; | |
} | |
#myclock { | |
position: absolute; | |
bottom: 78px; | |
left: -21px; | |
} | |
#map { | |
width: auto; | |
height: 100%; | |
} | |
svg{ | |
stroke: #DFDFDF; | |
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; | |
} | |
#rim { | |
fill: none; | |
stroke: #999; | |
stroke-width: 3px; | |
} | |
.second-hand{ | |
stroke-width:3; | |
} | |
.minute-hand{ | |
stroke-width:8; | |
stroke-linecap:round; | |
} | |
.hour-hand{ | |
stroke-width:12; | |
stroke-linecap:round; | |
} | |
.hands-cover{ | |
stroke-width:3; | |
fill:#fff; | |
} | |
.second-tick{ | |
stroke-width:3; | |
fill:#000; | |
} | |
.hour-tick{ | |
stroke-width:4; //same as the miute hand | |
} | |
.second-label{ | |
font-size: 12px; | |
} | |
.hour-label{ | |
font-size: 24px; | |
} | |
</style> | |
<body> | |
<div id="map"></div> | |
<div id="myclock" style="margin-top:100px"></div> | |
<script src="https://d3js.org/d3.v3.min.js"></script> | |
<script src="d3clock.js"></script> | |
<script src="https://cartodb-libs.global.ssl.fastly.net/cartodb.js/v3/3.13/cartodb.js"></script> | |
<script> | |
//instantiate leaflet map | |
var map = new L.Map('map', { | |
center: [30,0], | |
zoom: 2 | |
}); | |
//add CartoDB's "Darkmatter" basemap | |
L.tileLayer('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', { | |
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="http://cartodb.com/attributions">CartoDB</a>' | |
}).addTo(map); | |
//add CartoDB anonymous torque layer for earthquake data | |
cartodb.createLayer(map, { | |
type: "torque", | |
order: 1, | |
options: { | |
query: "", | |
table_name: "all_day", | |
user_name: "chriswhong", | |
tile_style: '/** torque visualization */ Map { -torque-frame-count:512; -torque-animation-duration:15; -torque-time-attribute:"time"; -torque-aggregation-function:"count(cartodb_id)"; -torque-resolution:2; -torque-data-aggregation:linear; } #earthquakes{ comp-op: lighter; marker-fill-opacity: 0.9; marker-line-color: #FFF; marker-line-width: 0; marker-line-opacity: 1; marker-type: ellipse; marker-width: 6; marker-fill: #5CA2D1; } #earthquakes[frame-offset=1] { marker-width:8; marker-fill-opacity:0.45; } #earthquakes[frame-offset=2] { marker-width:10; marker-fill-opacity:0.225; } #earthquakes[frame-offset=3] { marker-width:12; marker-fill-opacity:0.15; } #earthquakes[frame-offset=4] { marker-width:14; marker-fill-opacity:0.1125; } #earthquakes[frame-offset=5] { marker-width:16; marker-fill-opacity:0.09; }' | |
} | |
},{ | |
https: true | |
}).done(function(layer) { | |
layer.addTo(map); | |
//create clock | |
var clock = new Clock('myclock',200); | |
clock.draw(); | |
layer.setZIndex(5); | |
//tap into torque's change method to update the clock | |
layer.on('change:time', function(changes) { | |
var time = changes.time; | |
clock.updateData(time); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment