Adapting the state grid for use as an overview/minimap. When you zoom in on a state the counties for that state are rendered. This technique could be used to render subsets of larget datasets at the appropriate zoom level.
Map zooming from /mbostock/2206590
forked from mbostock's block: State Grid
xxxxxxxxxx
<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>
https://d3js.org/d3.v3.min.js
https://d3js.org/topojson.v1.min.js