// width and height var width = 1160, height = 960; // define map projection var projection = d3.geo.albersUsa() .translate([width/2, height/2]) .scale([1500]); // define path generator var path = d3.geo.path() .projection(projection); // create an svg element var svg = d3.select("body") .append("svg") .attr("width", width) .attr("height", height); svg.append("rect") .attr("class", "background") .attr("width", width) .attr("height", height) .on("click", clicked); var g = svg.append("g"); var padding = 20; // load both json files and parse them when loaded d3.queue(2) .defer(d3.json, 'us.json') .defer(d3.json, 'locations.json') .awaitAll(main); function main(error, data) { if (error) console.warn(error); parseUS(data[0]); parseLocations(data[1]); } function parseUS(us) { g.append("g") .attr("id", "states") .selectAll("path") .data(topojson.feature(us, us.objects.states).features) .enter().append("path") .attr("d", path); // .on("click", clicked); g.append("path") .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })) .attr("id", "state-borders") .attr("d", path); } function parseLocations(locations) { // draw my location data svg.selectAll("circle") .data(locations) .enter() .append("circle") .on("click", function(d){ console.log(d); }) .transition() .delay(function(d, i) { return i * 100}) // Scott Murray recommends putting delay before duration. .duration(500) .ease("linear") //change rate of motion to linear, not variable (the default setting) .each("start", function() { d3.select(this) .attr("fill", "yellow") .attr("r", 5); }) .attr("cx", function(d){ return projection([d.lon, d.lat])[0]; }) .attr("cy", function(d) { return projection([d.lon, d.lat])[1]; }) .each("end", function(){ d3.select(this) .attr("fill", "rgba(255,0,255,.25)") .attr('r', 8); }); svg.selectAll("text") .data(locations) .enter() .append("text") .transition() .delay(function(d,i) { return i * 100 }) .duration(500) .ease("linear") .each("start", function(){ d3.select(this) .attr("id", "labels-before") }) .text(function(d){ return (new Date(d.t*1000)).toDateString(); //hella awesome! converts unix epoch time stamp to a human readable format }) .attr("x", function(d){ return (projection([d.lon, d.lat])[0])+10; }) .attr("y", function(d){ return (projection([d.lon, d.lat])[1])-10; }) .each("end", function(){ d3.select(this) .attr("id", "labels-after") }); } // forget why I had this function function clicked(d) { var x, y, k; if (d && centered !== d) { var centroid = circle.centroid(d); x = centroid[0]; y = centroid[1]; k = 4; centered = d; } else { x = width / 2; y = height / 2; k = 1; centered = null; } g.selectAll("circle") .classed("active", centered && function(d) { return d === centered; }); g.transition() .duration(750) .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") .style("stroke-width", 1.5 / k + "px"); }