Skip to content

Instantly share code, notes, and snippets.

@chriswhong
Last active May 29, 2019 21:11
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save chriswhong/eafdf8514575bca90b48 to your computer and use it in GitHub Desktop.
Animated D3 Clock in Torque
//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");
}
<!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: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <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