Skip to content

Instantly share code, notes, and snippets.

@jhubley
Last active August 29, 2015 14:16
Show Gist options
  • Save jhubley/68423588d4b15bea5236 to your computer and use it in GitHub Desktop.
Save jhubley/68423588d4b15bea5236 to your computer and use it in GitHub Desktop.
time lapse of circles

Time lapse. Data is totally without meaning. There's not even a y axis. A basic template, needs to be cleaned up a bit.

//Speed & animation-control variables
var maprate = 4760/12,
pause=0,
timepause=0,
start = 0,
interval,
loop,
dateiter;
//Data parameter variables
var minyr,
maxyr,
dates,
years;
//Selection variables
var slider,
handle,
brush,
timer,
timeaxis,
timescale = d3.time.scale(),
datemark;
var timepad = 100; //bottom padding for slider
var width = Math.max(960, window.innerWidth),
height = Math.max(700, window.innerHeight);
// load data
d3.csv("time.csv",
type,
function(error, data) {
dates = d3.set(data.map(function(d) {return d.Date;})).values().map(function(z) {return new Date(z);});
years = d3.set(data.map(function(d) {return +d.Date.getFullYear();})).values().map(function(z) {return +z;});
minyr = d3.min(years);
maxyr = d3.max(years);
timescale
.rangeRound([0,width - 40])
.clamp(true)
;
timeaxis = d3.svg.axis()
.scale(timescale)
.orient("bottom")
.tickSize(0)
.tickPadding(12)
.ticks(0)
;
sliderbox = d3.select("#sliderbox")
.attr("width",1800);
timer = sliderbox.append("g");
timescale .domain([new Date(minyr,0,1),new Date(maxyr,12,31)]);
timer
.attr("class", "x axis")
.attr("transform","translate(" + 20 + "," + Math.floor((height - (timepad/2))) + ")")
.call(timeaxis)
.select(".domain")
brush = d3.svg.brush()
.x(timescale)
.extent([0,0])
.on("brush",function() { //Now separate into mousedown -> clearInterval, drag -> animate, mouseup -> setInterval components
var mouseval = timescale.invert(d3.mouse(this)[0]);
var val = new Date(mouseval.getFullYear(),12);
var strval = val.toISOString();
dateiter = dates.map(function(d) {return d.toISOString();}).indexOf(strval);
brush.extent([val,val]);
//handle.attr("cx",timescale(val));
handle.attr("transform","translate(" + timescale(val) + ",0)")
clearInterval(interval);
update(data,val);
interval = setInterval(loop,maprate);
})
;
slider = timer
.append("g")
.attr("class","slider")
.call(brush)
;
slider.selectAll(".extent,.resize")
.remove();
dateiter = 0;
handle = slider .append("g")
.attr("class","handle preload")
.attr("transform","translate(" + timescale(dates[0]) + ",0)");
handle.append("line")
.attr("class","datemark outer preload");
handle.append("line")
.attr("class","datemark inner preload");
handle.append("text")
.attr("class","datemark label")
.attr("y",-12)
.attr("x",0)
.attr("text-anchor","middle");
d3.selectAll(".datemark.preload") // size of brush dragger
.attr("x1",0)
.attr("x2",0)
.attr("y1",-5)
.attr("y2",5);
dateiter = 0; // date incrementer - start
loop = function(){
clearInterval(interval);
if ((timepause == 0 && pause == 0) || start == 0) {
update(data,dates[dateiter]);
if (dateiter < dates.length - 1) {++dateiter;}
else {
dateiter = 0;
timepause=1;
setTimeout(function(){timepause = 0;},3000);
}
}
start = 1;
interval = setInterval(loop, maprate);
}
interval = setInterval(loop, maprate);
}); //end data callback
function update(data,date) {
var yr = date.getFullYear(); // spits out the years for slider
var usedat = data.filter(yrfilter(yr));
var curr = [timescale(date)];
handle
.transition(50)
.attr("transform",function(d) {return "translate(" + Math.floor(curr) + ",0)"});
timer.selectAll(".datemark,.handle") // point that moves on timer
.classed('preload',0);
timer.select(".datemark.label")
.text(d3.time.format("%Y")(date));
timer.select(".datemark.labelbox")
.attr("height", 50)
.attr("width", 50)
.attr("x", 5)
.attr("y",-12)
.style("fill-opacity",0);
var datapoints = d3.select("#points").selectAll("circle").data(data)
.enter()
.append("circle")
.attr("class", function(d){return "dot " +d.Year});
var circles = d3.selectAll(".dot")
.classed({'preload': false, 'loaded': true})
.data(usedat, function(d) { return d ? d.Radius : this.id; }, function(d) { return d ? d.x : this.id; }, function(d) { return d ? d.y : this.id; });
circles
.transition()
.duration(475)
.attr("r", function(d){return d.Radius})
.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y})
.style("fill", "#ff0000")
.style("opacity", 1)
.transition()
.duration(300)
.attr("r", function(d){return d.Radius})
.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y})
.style("fill", "#ff0000")
.style("opacity", 0.7)
.transition()
.duration(250)
.attr("r", function(d){return d.Radius})
.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y})
.style("fill", "#ff0000")
.style("opacity", 0.5)
.transition()
.duration(150)
.attr("r", function(d){return d.Radius})
.attr("cx", function(d){return d.x})
.attr("cy", function(d){return d.y})
.style("fill", "#ff0000")
.style("opacity", 0.2)
.remove();
} //end update
//Filter by year.
function yrfilter(year) {
return function(element) {
return element.Year == year;
}
}
function type(d) {
d.Year = +d.Year;
d.Date = new Date(d.Year,12);
return d;
}
<!DOCTYPE html>
<head>
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400' rel='stylesheet' type='text/css'>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.geo.tile.v0.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<style>
body {
font-family:Helvetica, Arial, sans-serif;
}
.datemark.label {
font-size: 18px;
font-weight: 400;
}
.yearlabel {
font: 8px;
fill-opacity: 1;
color: #000;
}
.axis path,
.axis line {
fill: #888888;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis .domain {
fill: none;
stroke: #888;
stroke-width: 8px;
stroke-linecap: round;
}
.axis .yearmark {
stroke-width: 6px;
stroke-linecap: round;
}
.datemark {
color: rgb(0,0,0);
stroke-opacity: 1;
}
.datemark.outer {
stroke-width: 7px;
stroke: #000;
stroke-linecap: round;
}
.datemark.inner {
stroke-width: 5px;
stroke: #fff;
stroke-linecap: round;
}
.datemark.center {
stroke-width: 1px;
stroke: #000;
}
.preload {
fill-opacity: .000001;
stroke-opacity: .000001;
}
.datemark.labelbox {
stroke-width: 0 ;
fill: rgba(0,0,0,0.8);
}
#map{
width:100%;
height:900px;
}
#points{
width:600px;
height:600px;
}
.dot{
fill: #ffffff;
}
</style>
</head>
<body>
<script src="circles.js"></script>
<svg id="map">
<svg id="points"></svg>
<svg id="sliderbox"></svg>
</svg>
</body>
</html>
Year Radius x y
2000 22 157 390
2000 40 180 230
2001 9 120 344
2001 33 180 490
2002 3 160 388
2002 5 144 240
2003 4 155 38
2003 7 122 411
2004 20 120 520
2004 10 145 350
2004 8 190 137
2004 4 178 126
2005 2 112 180
2005 23 57 87
2006 5 45 22
2006 7 20 44
2007 7 230 21
2007 17 344 38
2008 1 490 40
2008 2 388 38
2009 3 22 155
2009 12 90 122
2010 6 78 120
2010 3 12 145
2011 8 257 435
2011 11 545 312
2012 9 420 544
2012 22 380 221
2013 13 260 568
2013 2 44 140
2014 20 55 38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment