Skip to content

Instantly share code, notes, and snippets.

@mbostock
Forked from mbostock/.block
Last active November 10, 2020 18:56
Show Gist options
  • Save mbostock/2374239 to your computer and use it in GitHub Desktop.
Save mbostock/2374239 to your computer and use it in GitHub Desktop.
Zoomable Geography
license: gpl-3.0
redirect: https://observablehq.com/@d3/zoom-to-bounding-box
.DS_Store
build
node_modules
Makefile

An example of d3.behavior.zoom and d3.geo.path. By modifying the transform, the browser can rapidly redraw geographic features while panning and zooming, without the overhead of reprojection. This technique can be extended by combining with d3.geo.tile.

#!/usr/bin/env node
var fs = require("fs");
var idProperty = process.argv[2],
collection = JSON.parse(fs.readFileSync("/dev/stdin")),
featureIds = {};
collection.features = collection.features.filter(function(feature) {
var id = feature.properties[idProperty];
if (id == null) throw new Error("id is required for geouniq");
if (!(id in featureIds)) {
featureIds[id] = 1;
return true;
}
});
console.log(JSON.stringify(collection));
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.overlay {
fill: none;
pointer-events: all;
}
.state {
fill: #aaa;
}
.county-border,
.state-border {
fill: none;
stroke: #fff;
stroke-linejoin: round;
stroke-linecap: round;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var path = d3.geo.path()
.projection(null);
var zoom = d3.behavior.zoom()
.translate([0, 0])
.scale(1)
.scaleExtent([1, 8])
.on("zoom", zoomed);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var features = svg.append("g");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.call(zoom);
d3.json("us.json", function(error, us) {
if (error) throw error;
features.append("path")
.datum(topojson.feature(us, us.objects.states))
.attr("class", "state")
.attr("d", path);
features.append("path")
.datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
.attr("class", "state-border")
.attr("d", path)
.style("stroke-width", "1.5px");
features.append("path")
.datum(topojson.mesh(us, us.objects.counties, function(a, b) { return a !== b && !(a.id / 1000 ^ b.id / 1000); }))
.attr("class", "county-border")
.attr("d", path)
.style("stroke-width", ".5px");
});
function zoomed() {
features.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
features.select(".state-border").style("stroke-width", 1.5 / d3.event.scale + "px");
features.select(".county-border").style("stroke-width", .5 / d3.event.scale + "px");
}
d3.select(self.frameElement).style("height", height + "px");
</script>
{
"name": "anonymous",
"version": "0.0.1",
"private": true,
"devDependencies": {
"topojson": "1"
}
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@stefanborchardt
Copy link

I combined this example with raster tiles, also using https://bl.ocks.org/mbostock/5342063 as a blueprint. There is a small scaling problem when tile zoom levels change, but that could be caused by the rasterizer.
https://bl.ocks.org/stefanborchardt/171e6633cc1124254909

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment