|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
body { |
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
width: 960px; |
|
height: 500px; |
|
position: relative; |
|
} |
|
.states { |
|
fill: #ccc; |
|
stroke: #f7f7f7; |
|
stroke-width: .25; |
|
} |
|
.link{ |
|
stroke: #ff0000; |
|
fill:none; |
|
stroke-opacity: 0.2; |
|
pointer-events: none; |
|
} |
|
.world{ |
|
stroke: none; |
|
fill: #ccc; |
|
} |
|
|
|
</style> |
|
<body> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="http://d3js.org/topojson.v1.min.js"></script> |
|
<script src="http://d3js.org/queue.v1.min.js"></script> |
|
<script> |
|
|
|
var width = 960, |
|
height = 500; |
|
|
|
var projection = d3.geo.mercator() |
|
.translate([480, 350]) |
|
.scale(160); |
|
|
|
var path = d3.geo.path().projection(projection); |
|
|
|
var linkWidth = d3.scale.linear() |
|
.range([0,5]); |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var desc; |
|
|
|
var loadNotify = svg.append("text") |
|
.attr("x", 10) |
|
.attr("y", 25) |
|
.text("Loading..."); |
|
|
|
queue() |
|
.defer(d3.json, "us.json") |
|
.defer(d3.json, "us-state-centroids.json") |
|
.defer(d3.json, "world-50m.json") |
|
.defer(d3.json, "world_centroids.json") |
|
.defer(d3.tsv, "world-country-names.tsv") |
|
.defer(d3.csv, "refugee_id.csv") |
|
.await(ready); |
|
|
|
function ready(error, us, centroid, world, world_cen, world_names, refugee) { |
|
|
|
loadNotify.remove(); |
|
|
|
var nested_data = d3.nest() |
|
.key(function(d) { return d.fips; }) |
|
.rollup(function(state) { return d3.sum(state, function (d){return d.value}); }) |
|
.entries(refugee); |
|
|
|
var nested_world = d3.nest() |
|
.key(function(d) { return d.id; }) |
|
.rollup(function(country) { return d3.sum(country, function (d){return d.value}); }) |
|
.entries(refugee); |
|
|
|
linkWidth.domain([0, d3.max(refugee, function(d){return +d.value})]) |
|
|
|
svg.append("g") |
|
.attr("class", "world") |
|
.selectAll("path") |
|
.data(topojson.feature(world, world.objects.countries).features) |
|
.enter() |
|
.append("path") |
|
.attr("d", path) |
|
.style("fill", function (d){ return checkInvolveCountries(d.id) ? "#ccc" : "#eee"}); |
|
|
|
svg.append("g") |
|
.attr("class", "states") |
|
.selectAll("path") |
|
.data(topojson.feature(us, us.objects.states).features) |
|
.enter() |
|
.append("path") |
|
.attr("d", path) |
|
.style("fill", function (d){ return checkInvolveStates(d.id) ? "#ccc" : "#eee"}); |
|
|
|
desc = svg.append("text") |
|
.attr("x", 10) |
|
.attr("y", height - 10) |
|
.text(""); |
|
|
|
svg.select('.world').selectAll('path').on('mouseover', function (e){ |
|
if(checkInvolveCountries(e.id)){ |
|
desc.text(getCountryName(e.id) + ": " + getCountryTotal(e.id) + " exited"); |
|
|
|
d3.select('.states') |
|
.selectAll('path') |
|
.transition() |
|
.style('fill', function (d){ |
|
if( getInvolvedStates(e.id, d.id) ){ |
|
return '#4adda1'; |
|
} |
|
else if( checkInvolveStates(d.id) ){ |
|
return "#ccc"; |
|
} |
|
else{ |
|
return "#eee"; |
|
} |
|
}); |
|
|
|
d3.select(this).style('fill', '#5594b7'); |
|
svg.select(".arc").selectAll("path") |
|
.transition() |
|
.style('stroke-opacity', function (d){ |
|
if(+d.id === +e.id){ |
|
return 0.2; |
|
} |
|
else{ |
|
return 0; |
|
} |
|
}); |
|
}; |
|
} ); |
|
svg.select('.world').selectAll('path').on('mouseout', function (e){ |
|
|
|
d3.select('.states') |
|
.selectAll('path') |
|
.style("fill", function (d){ return checkInvolveStates(d.id) ? "#ccc" : "#eee"}); |
|
|
|
d3.select('.world') |
|
.selectAll('path') |
|
.style("fill", function (d){ return checkInvolveCountries(d.id) ? "#ccc" : "#eee"}); |
|
|
|
desc.text(''); |
|
|
|
svg.select(".arc").selectAll("path").transition().style('stroke-opacity', 0.2); |
|
|
|
} ); |
|
|
|
svg.select('.states').selectAll('path').on('mouseover', function (e){ |
|
|
|
if(checkInvolveStates(e.id)){ |
|
desc.text(getStateName(e.id) + ": " + getValue(e.id) + " entered"); |
|
|
|
|
|
d3.select('.world') |
|
.selectAll('path') |
|
.transition() |
|
.style('fill', function (d){ |
|
if( getInvolvedCountries(e.id, d.id) ){ |
|
return '#5594b7'; |
|
} |
|
else if( checkInvolveCountries(d.id) ){ |
|
return "#ccc"; |
|
} |
|
else{ |
|
return "#eee"; |
|
} |
|
}); |
|
|
|
d3.select(this).style('fill', '#4adda1'); |
|
svg.select(".arc").selectAll("path") |
|
.transition() |
|
.style('stroke-opacity', function (d){ |
|
if(+d.fips === +e.id){ |
|
return 0.2; |
|
} |
|
else{ |
|
return 0; |
|
} |
|
}); |
|
}; |
|
} ); |
|
svg.select('.states').selectAll('path').on('mouseout', function (e){ |
|
d3.select('.states') |
|
.selectAll('path') |
|
.style("fill", function (d){ return checkInvolveStates(d.id) ? "#ccc" : "#eee"}); |
|
|
|
d3.select('.world') |
|
.selectAll('path') |
|
.style("fill", function (d){ return checkInvolveCountries(d.id) ? "#ccc" : "#eee"}); |
|
|
|
desc.text(''); |
|
svg.select(".arc").selectAll("path").transition().style('stroke-opacity', 0.2); |
|
|
|
} ); |
|
|
|
svg.append("g") |
|
.attr("class", "arc") |
|
.selectAll('path') |
|
.data(refugee) |
|
.enter() |
|
.append("path") |
|
.attr('class', 'link') |
|
.attr('d', function (d){ return path(getArc(d.id, d.fips))}) |
|
.style('stroke-width', function (d){ return linkWidth(d.value)}); |
|
|
|
function getValue(id){ |
|
|
|
var rval; |
|
nested_data.map(function (d){ |
|
if(+d.key === id){ |
|
rval = d; |
|
} |
|
}); |
|
|
|
if(rval == undefined){ |
|
return 0; |
|
} |
|
else{ |
|
return rval.values; |
|
} |
|
|
|
}; |
|
function getCountryTotal(id){ |
|
var match = nested_world.filter(function (d){ |
|
return +id === +d.key; |
|
}); |
|
return match[0].values; |
|
}; |
|
|
|
function getCountryName(id){ |
|
|
|
var match = world_names.filter(function (d){ |
|
return +id === +d.id; |
|
}); |
|
|
|
return match[0].name; |
|
}; |
|
|
|
function getStateName(id){ |
|
|
|
var match = centroid.features.filter( function (d){ |
|
return +id === +d.id |
|
}); |
|
|
|
return match[0].properties.name |
|
}; |
|
|
|
function getArc(src,dest){ |
|
var stateMatch = centroid.features.filter(function(d){ |
|
return +d.id === +dest; |
|
}); |
|
|
|
var countryMatch = world_cen.filter(function(d){ |
|
return +d.id === +src; |
|
}); |
|
|
|
return {type: "LineString", coordinates: [stateMatch[0].geometry.coordinates, countryMatch[0].centroid]} |
|
|
|
}; |
|
|
|
function checkInvolveCountries(id){ |
|
var inv = refugee.filter(function (d){ |
|
return +d.id === +id; |
|
}); |
|
return (inv.length > 0); |
|
}; |
|
|
|
function checkInvolveStates(id){ |
|
var inv = refugee.filter(function (d){ |
|
return +d.fips === +id; |
|
}); |
|
return (inv.length > 0); |
|
}; |
|
|
|
function getInvolvedStates(id, id2){ |
|
var matches = refugee.filter(function (d){ |
|
return +d.id === +id; |
|
}); |
|
|
|
var involved = matches.filter(function (d){ |
|
return +d.fips === +id2; |
|
}); |
|
|
|
return involved.length > 0; |
|
}; |
|
function getInvolvedCountries(id, id2){ |
|
|
|
var matches = refugee.filter(function (d){ |
|
return +d.fips === +id; |
|
}); |
|
|
|
var involved = matches.filter(function (d){ |
|
return +d.id === +id2; |
|
}); |
|
|
|
return involved.length > 0; |
|
}; |
|
}; |
|
</script> |