Mouseover to see flights originating at the specified airport. The cool thing about this technique is that the interaction requires zero JavaScript — it’s all done in CSS using the :hover state to toggle visibility of an airport’s associated outgoing flight routes.
forked from mbostock's block: Voronoi Arc Map
forked from anonymous's block: Voronoi Arc Map
xxxxxxxxxx
<meta charset="utf-8">
<style>
.states {
fill: #ccc;
}
.state-borders {
fill: none;
stroke: #fff;
stroke-width: 1.5px;
stroke-linejoin: round;
stroke-linecap: round;
}
.airport-arcs {
display: none;
fill: none;
stroke: #000;
}
.airport-cell {
fill: none;
pointer-events: all;
}
.airports circle {
fill: steelblue;
stroke: #fff;
pointer-events: none;
}
.airport:hover .airport-arcs {
display: inline;
}
/* svg:not(:hover) .airport-cell {
stroke: #000;
stroke-opacity: .2;
} */
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geo.albers()
.translate([width / 2, height / 2])
.scale(1080);
var path = d3.geo.path()
.projection(projection);
var voronoi = d3.geom.voronoi()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.clipExtent([[0, 0], [width, height]]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
queue()
.defer(d3.json, "https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json")
.defer(d3.csv, "airports.csv")
.defer(d3.csv, "flights.csv")
.await(ready);
function ready(error, us, airports, flights) {
if (error) throw error;
var airportById = d3.map(),
positions = [];
airports.forEach(function(d) {
airportById.set(d.iata, d);
d.outgoing = [];
d.incoming = [];
});
flights.forEach(function(flight) {
var source = airportById.get(flight.origin),
target = airportById.get(flight.destination),
link = {source: source, target: target};
source.outgoing.push(link);
target.incoming.push(link);
});
airports = airports.filter(function(d) {
if (d.count = Math.max(d.incoming.length, d.outgoing.length)) {
d[0] = +d.longitude;
d[1] = +d.latitude;
var position = projection(d);
d.x = position[0];
d.y = position[1];
return true;
}
});
voronoi(airports)
.forEach(function(d) { d.point.cell = d; });
svg.append("path")
.datum(topojson.feature(us, us.objects.land))
.attr("class", "states")
.attr("d", path);
svg.append("path")
.datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
.attr("class", "state-borders")
.attr("d", path);
var airport = svg.append("g")
.attr("class", "airports")
.selectAll("g")
.data(airports.sort(function(a, b) { return b.count - a.count; }))
.enter().append("g")
.attr("class", "airport");
airport.append("path")
.attr("class", "airport-cell")
.attr("d", function(d) { return d.cell.length ? "M" + d.cell.join("L") + "Z" : null; });
airport.append("g")
.attr("class", "airport-arcs")
.selectAll("path")
.data(function(d) { return d.outgoing; })
.enter().append("path")
.attr("d", function(d) { return path({type: "LineString", coordinates: [d.source, d.target]}); });
airport.append("circle")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.attr("r", function(d, i) { return Math.sqrt(d.count); });
}
</script>
https://d3js.org/d3.v3.min.js
https://d3js.org/queue.v1.min.js
https://d3js.org/topojson.v1.min.js