Hover to see flight routes associated with each airport. The interaction does not require JavaScript event handlers: it’s done using the CSS :hover state!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.land {
fill: #ddd;
}
.state-borders {
fill: none;
stroke: #fff;
}
.airport-arc {
fill: none;
}
.airport:hover .airport-arc {
stroke: #f00;
}
.airport-cell {
fill: none;
stroke: #000;
stroke-opacity: 0.1;
pointer-events: all;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var projection = d3.geoAlbers()
.translate([width / 2, height / 2])
.scale(1280);
var radius = d3.scaleSqrt()
.domain([0, 100])
.range([0, 14]);
var path = d3.geoPath()
.projection(projection)
.pointRadius(2.5);
var voronoi = d3.voronoi()
.extent([[-1, -1], [width + 1, height + 1]]);
d3.queue()
.defer(d3.json, "/mbostock/raw/4090846/us.json")
.defer(d3.csv, "airports.csv", typeAirport)
.defer(d3.csv, "flights.csv", typeFlight)
.await(ready);
function ready(error, us, airports, flights) {
if (error) throw error;
var airportByIata = d3.map(airports, function(d) { return d.iata; });
flights.forEach(function(flight) {
var source = airportByIata.get(flight.origin),
target = airportByIata.get(flight.destination);
source.arcs.coordinates.push([source, target]);
target.arcs.coordinates.push([target, source]);
});
airports = airports
.filter(function(d) { return d.arcs.coordinates.length; });
svg.append("path")
.datum(topojson.feature(us, us.objects.land))
.attr("class", "land")
.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);
svg.append("path")
.datum({type: "MultiPoint", coordinates: airports})
.attr("class", "airport-dots")
.attr("d", path);
var airport = svg.selectAll(".airport")
.data(airports)
.enter().append("g")
.attr("class", "airport");
airport.append("title")
.text(function(d) { return d.iata + "\n" + d.arcs.coordinates.length + " flights"; });
airport.append("path")
.attr("class", "airport-arc")
.attr("d", function(d) { return path(d.arcs); });
airport.append("path")
.data(voronoi.polygons(airports.map(projection)))
.attr("class", "airport-cell")
.attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; });
}
function typeAirport(d) {
d[0] = +d.longitude;
d[1] = +d.latitude;
d.arcs = {type: "MultiLineString", coordinates: []};
return d;
}
function typeFlight(d) {
d.count = +d.count;
return d;
}
</script>