|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<title>Non-Contiguous Cartogram</title> |
|
<style> |
|
|
|
.land { |
|
fill: #fff; |
|
stroke: #ccc; |
|
} |
|
|
|
.state { |
|
stroke: #666; |
|
opacity: .5; |
|
} |
|
|
|
</style> |
|
<body> |
|
<script src="//d3js.org/d3.v3.min.js"></script> |
|
<script src="//d3js.org/topojson.v1.min.js"></script> |
|
<script> |
|
|
|
var path = d3.geo.path(); |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", 1200) |
|
.attr("height", 500); |
|
|
|
// set up pie chart |
|
var radius = 130; |
|
var arc = d3.svg.arc() |
|
.outerRadius(radius - 10) |
|
.innerRadius(0); |
|
|
|
|
|
var sortSlices = function(a,b){ |
|
if(a.include == b.include) { |
|
return b.GDP - a.GDP |
|
} |
|
return +b.include - +a.include |
|
} |
|
|
|
|
|
|
|
var updatePie = function(data){ |
|
var pie = d3.layout.pie() |
|
.sort(null) |
|
.value(function(d) { return +d.GDP; }); |
|
|
|
svg.selectAll(".arc").data([]).exit().remove() |
|
|
|
var g = svg.selectAll(".arc") |
|
.data(pie(data.sort(sortSlices)), function(d){return d.data.State}) |
|
console.log(pie(data.sort(sortSlices))) |
|
|
|
g.enter().append("g") |
|
.attr("transform", "translate(950,300)") |
|
.attr("class", "arc") |
|
.append("path") |
|
.attr("class", 'stateArc'); |
|
|
|
d3.selectAll(".stateArc").attr("d", arc).style("fill", colorSelectedArc); |
|
|
|
|
|
} |
|
|
|
|
|
d3.csv('namesToId.csv', function(error, stateNamesIds){ |
|
|
|
var stateAbbrLookup = {} |
|
|
|
var stateIdLookup = stateNamesIds.reduce(function(map, obj) { |
|
map[obj.id] = obj.name |
|
stateAbbrLookup[obj.id] = obj.abb |
|
return map; |
|
}, {}); |
|
|
|
|
|
d3.csv('stateGDP2015.csv', function(error, gdp){ |
|
|
|
var max = d3.max(gdp, function(d) { return +d.GDP;} ); |
|
|
|
var gdpByStateLookup = gdp.reduce(function(map, obj) { |
|
if(obj.GDP > max){ |
|
max = obj.GDP |
|
} |
|
map[obj.State] = {'gdp': +obj.GDP, 'include': +obj.include}; |
|
return map; |
|
}, {}); |
|
|
|
|
|
d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json", function(error, us) { |
|
if (error) throw error; |
|
|
|
// outline of US |
|
svg.append("path") |
|
.datum(topojson.feature(us, us.objects.land)) |
|
.attr("class", "land") |
|
.attr("d", path); |
|
|
|
// function to use include boolean to decide color |
|
colorSelected = function(d){ |
|
var data = gdpByStateLookup[stateIdLookup[d.id]]; |
|
if(data && data.include) { |
|
return "#9fc2c6" |
|
} |
|
return "#ccc" |
|
} |
|
colorSelectedArc = function(d) { |
|
return +d.data.include ? '#9fc2c6' : '#ddd' |
|
} |
|
|
|
var state = svg.selectAll(".state") |
|
.data(topojson.feature(us, us.objects.states).features, function(d){return d.id}) |
|
.enter().append("g") |
|
.attr("transform", function(d){ |
|
var center = path.centroid(d); |
|
return "translate(" + center[0] + "," + center[1] + ")" |
|
}) |
|
|
|
state.append("text") |
|
.attr("transform", function(d){return "translate(-11,5)"}) |
|
.attr("fill", "lightgrey") |
|
.text( |
|
function(d){ |
|
return stateAbbrLookup[d.id] |
|
} |
|
) |
|
|
|
state.append("circle") |
|
.attr("class", "state") |
|
.attr("r", function(d){ |
|
var data = gdpByStateLookup[stateIdLookup[d.id]]; |
|
return data ? Math.sqrt(data.gdp / max) * 50 : 0 |
|
}) |
|
.style("fill", colorSelected) |
|
.on('click', function(d){ |
|
gdpByStateLookup[stateIdLookup[d.id]].include = !gdpByStateLookup[stateIdLookup[d.id]].include; |
|
|
|
gdp.forEach(function(state){ |
|
if(state.State == stateIdLookup[d.id]){ |
|
state.include = !+state.include} |
|
}) |
|
|
|
d3.selectAll(".state") |
|
.style("fill", colorSelected); |
|
|
|
updatePie(gdp) |
|
|
|
|
|
}) |
|
|
|
updatePie(gdp) |
|
}); |
|
}); |
|
}) |
|
|
|
</script> |