Skip to content

Instantly share code, notes, and snippets.

@larsvers
Forked from mbostock/.block
Created November 26, 2018 22:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save larsvers/c2d9c9bcfe168b2e94327718235bfaa6 to your computer and use it in GitHub Desktop.
Save larsvers/c2d9c9bcfe168b2e94327718235bfaa6 to your computer and use it in GitHub Desktop.
Zoom to Bounding Box II
license: gpl-3.0

A variant of the Zoom to Bounding Box example that uses zoom transitions to smoothly interpolate between different views. This example also allows you to freely pan and zoom with the mouse (or touch).

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.background {
fill: none;
pointer-events: all;
}
.feature {
fill: #ccc;
cursor: pointer;
}
.feature.active {
fill: orange;
}
.mesh {
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: 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,
active = d3.select(null);
var projection = d3.geo.albersUsa()
.scale(1000)
.translate([width / 2, height / 2]);
var zoom = d3.behavior.zoom()
.translate([0, 0])
.scale(1)
.scaleExtent([1, 8])
.on("zoom", zoomed);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.on("click", stopped, true);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", reset);
var g = svg.append("g");
svg
.call(zoom) // delete this line to disable free zooming
.call(zoom.event);
d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
if (error) throw error;
g.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("d", path)
.attr("class", "feature")
.on("click", clicked);
g.append("path")
.datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
.attr("class", "mesh")
.attr("d", path);
});
function clicked(d) {
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bounds = path.bounds(d),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
function reset() {
active.classed("active", false);
active = d3.select(null);
svg.transition()
.duration(750)
.call(zoom.translate([0, 0]).scale(1).event);
}
function zoomed() {
g.style("stroke-width", 1.5 / d3.event.scale + "px");
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// If the drag behavior prevents the default click,
// also stop propagation so we don’t click-to-zoom.
function stopped() {
if (d3.event.defaultPrevented) d3.event.stopPropagation();
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment