|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<script src="//d3js.org/d3.v3.min.js"></script> |
|
<script src="//d3js.org/topojson.v1.min.js"></script> |
|
<style> |
|
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } |
|
#state-grid { |
|
position:absolute; |
|
top: 0; |
|
left: 0; |
|
} |
|
#map { |
|
position: absolute; |
|
width: 100%; |
|
height: 100%; |
|
} |
|
.state { |
|
cursor: pointer; |
|
} |
|
.state rect { |
|
fill: #dedede; |
|
fill-opacity: 0.4; |
|
rx: 3; |
|
ry: 3; |
|
} |
|
.selected rect { |
|
fill: steelblue; |
|
} |
|
|
|
.state text { |
|
font: 12px sans-serif; |
|
text-anchor: middle; |
|
} |
|
.state-boundary { |
|
fill: none; |
|
stroke: #111; |
|
} |
|
.county { |
|
fill: #d6fef1; |
|
stroke: #111; |
|
} |
|
</style> |
|
<svg id="map"></svg> |
|
<svg id="state-grid" width=400 height=200></svg> |
|
<script id="grid" type="text/plain"> |
|
ME |
|
WI VT NH |
|
WA ID MT ND MN IL MI NY MA |
|
OR NV WY SD IA IN OH PA NJ CT RI |
|
CA UT CO NE MO KY WV VA MD DE |
|
AZ NM KS AR TN NC SC |
|
OK LA MS AL GA |
|
HI AK TX FL |
|
</script> |
|
|
|
<script> |
|
|
|
var states = []; |
|
d3.select("#grid").text().split("\n").forEach(function(line, i) { |
|
var re = /\w+/g, m; |
|
while (m = re.exec(line)) states.push({ |
|
name: m[0], |
|
x: m.index / 3, |
|
y: i |
|
}); |
|
}); |
|
|
|
var minisvg = d3.select("#state-grid"); |
|
var miniwidth = 400; |
|
var miniheight = 200; |
|
|
|
var mapsvg = d3.select("#map").append("g"); |
|
var mapwidth = 960; |
|
var mapheight = 500; |
|
var scale0 = 1000; |
|
|
|
var centered; |
|
var selected; |
|
|
|
var allCounties = [] |
|
|
|
var zoom = d3.behavior.zoom() |
|
.translate([mapwidth / 2, mapheight / 2]) |
|
.scale(scale0) |
|
.scaleExtent([scale0, 10 * scale0]) |
|
.on("zoom", zoomed); |
|
|
|
var projection = d3.geo.albersUsa() |
|
.scale(scale0) |
|
.translate([mapwidth / 2, mapheight / 2]); |
|
|
|
var path = d3.geo.path() |
|
.projection(projection); |
|
|
|
function zoomed() { |
|
projection |
|
.translate(zoom.translate()) |
|
.scale(zoom.scale()); |
|
|
|
mapsvg.selectAll("path") |
|
.attr("d", path); |
|
mapsvg.selectAll("circle.city") |
|
.attr({ |
|
cx: getX, |
|
cy: getY |
|
}) |
|
} |
|
|
|
mapsvg.call(zoom) |
|
|
|
function clicked(d) { |
|
var x, y, k; |
|
console.log("clicked", d) |
|
|
|
if (d && centered !== d) { |
|
var centroid = path.centroid(d); |
|
x = centroid[0]; |
|
y = centroid[1]; |
|
k = 4; |
|
centered = d; |
|
} else { |
|
x = mapwidth / 2; |
|
y = mapheight / 2; |
|
k = 1; |
|
centered = null; |
|
} |
|
|
|
mapsvg.selectAll("path.state-boundary") |
|
.classed("active", centered && function(d) { return d === centered; }); |
|
|
|
mapsvg.transition() |
|
.duration(750) |
|
.attr("transform", "translate(" + mapwidth / 2 + "," + mapheight / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")") |
|
.style("stroke-width", 1.5 / k + "px"); |
|
|
|
mapsvg.selectAll("path.county") |
|
.transition().duration(300) |
|
.style("opacity", 0) |
|
.remove(); |
|
|
|
var counties = []; |
|
allCounties.forEach(function(c) { |
|
var sid = d.id+""; |
|
var cid = c.id+""; |
|
if(cid.slice(0,sid.length) === sid && cid.length - sid.length == 3) counties.push(c); |
|
}) |
|
console.log("counties", counties) |
|
var countyPaths = mapsvg |
|
.selectAll("path.county") |
|
.data(counties) |
|
countyPaths |
|
.enter().append("path").classed("county", true) |
|
.style("opacity", 0) |
|
|
|
countyPaths.attr("d", path) |
|
.transition() |
|
.duration(800) |
|
.style("opacity", 0.6) |
|
|
|
} |
|
|
|
|
|
|
|
var gridWidth = d3.max(states, function(d) { return d.x; }) + 1; |
|
var gridHeight = d3.max(states, function(d) { return d.y; }) + 1; |
|
var cellSize = 25; |
|
|
|
var state = minisvg.append("g") |
|
.attr("transform", "translate(" + miniwidth / 2 + "," + miniheight / 2 + ")scale(1)") |
|
.selectAll(".state") |
|
.data(states) |
|
.enter().append("g") |
|
.classed("state", true) |
|
.attr("transform", function(d) { return "translate(" + (d.x - gridWidth / 2) * cellSize + "," + (d.y - gridHeight / 2) * cellSize + ")"; }); |
|
|
|
state.append("rect") |
|
.attr("x", -cellSize / 2) |
|
.attr("y", -cellSize / 2) |
|
.attr("width", cellSize - 2) |
|
.attr("height", cellSize - 2); |
|
|
|
state.append("text") |
|
.attr("dy", ".35em") |
|
.attr("dx", "-.1em") |
|
.text(function(d) { return d.name; }); |
|
|
|
state.on("click", function(d) { |
|
console.log("clicked", d) |
|
var sel = d3.selectAll(".state-boundary").filter(function(a) { return a.properties.code === d.name}) |
|
var state = sel.data()[0] |
|
console.log("state", state) |
|
clicked(state); |
|
if(d3.select(this).classed("selected")) { |
|
d3.select(this).classed("selected", false) |
|
} else { |
|
minisvg.selectAll(".state").classed("selected", false) |
|
d3.select(this).classed("selected", true) |
|
} |
|
|
|
}); |
|
|
|
d3.json("us-named.json", function(error, us) { |
|
console.log("COUNTIES", topojson.feature(us, us.objects.counties).features); |
|
allCounties = topojson.feature(us, us.objects.counties).features; |
|
mapsvg |
|
.selectAll("path") |
|
.data(topojson.feature(us, us.objects.states).features) |
|
.enter().append("path").classed("state-boundary", true) |
|
.attr("d", path) |
|
|
|
//visualize # of counties |
|
}) |
|
|
|
</script> |