Skip to content

Instantly share code, notes, and snippets.

Last active October 2, 2023 22:14
Show Gist options
  • Save mbostock/4699541 to your computer and use it in GitHub Desktop.
Save mbostock/4699541 to your computer and use it in GitHub Desktop.
Zoom to Bounding Box
license: gpl-3.0

This example demonstrates how to compute a suitable translate and scale to zoom to the bounding box of a particular feature. Click on any state to zoom in; click on the focused state or the background to zoom out.

This variant uses transform transitions to change the viewport. A slightly better approach, and one that can also allow free panning and zooming with the mouse if desired, is to use zoom transitions.

<!DOCTYPE html>
<meta charset="utf-8">
.background {
fill: none;
pointer-events: all;
.feature {
fill: #ccc;
cursor: pointer;
} {
fill: orange;
.mesh {
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: round;
<script src="//"></script>
<script src="//"></script>
var width = 960,
height = 500,
active =;
var projection = d3.geo.albersUsa()
.translate([width / 2, height / 2]);
var path = d3.geo.path()
var svg ="body").append("svg")
.attr("width", width)
.attr("height", height);
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", reset);
var g = svg.append("g")
.style("stroke-width", "1.5px");
d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
if (error) throw error;
.data(topojson.feature(us, us.objects.states).features)
.attr("d", path)
.attr("class", "feature")
.on("click", clicked);
.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 ="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 = .9 / Math.max(dx / width, dy / height),
translate = [width / 2 - scale * x, height / 2 - scale * y];
.style("stroke-width", 1.5 / scale + "px")
.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
function reset() {
active.classed("active", false);
active =;
.style("stroke-width", "1.5px")
.attr("transform", "");
Copy link

rbelew commented Oct 28, 2013

(first i tried IRC, nobody listening. then i tried stackOverflow complained about me not meeting their quality standards?! sigh, a comment via github)

I've replicated this example, except mine does NOT zoom when i click a region? I've made a pastie of my version:

the regions render fine, i can click on each and get its name echoed to console, and the second echo of the 'b' var also looks correct?

anyone see a bug? i can also send along the opd_beats.json file if it'd help?

Copy link

I would like to know , it there is a way to add opacity to what is not selected,
For example when i select i state , i would like to have the selected state highlighted just like the example and make al other states covered with a transparent background.

Copy link

philiprhoades commented Jun 18, 2019

I can't get this to work - I get a blank screen - I inserted your code after this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">

and before this:


but no display and no errors - what am I missing?


Copy link

It's OK - I worked it what I was doing wrong . . now to do something like it for Australia . .

Copy link

Hi Mike,
I have a question for you concerning how you derive your scale .9 / Math.max(dx / width, dy / height). I understand that .9 value makes sure that we have a margin between the edges and the element we want to zoom to. I was wondering if there is a way to get a zero edge-to-edge margin. Furthermore, could you please help me understand how that 0.9 is arrived at? Is it a ratio between the SVG height & width?. Thanks
Regards Cyrus.

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