Last Updated: April 27, 2017
· sgruhier

Simplest way to add zoom/pan on d3.js (version 3 and 4)

I needed to add zoom/pan on d3.js visualisation. After a painful search on Google, I finally found a simple way to do it.

d3.js has everything to do it with only a few lines of code.

You just need to create a g element as first child of the SVG element and connect d3.behavior.zoom() behavior.

var svg ="body")
  .attr("width", "100%")
  .attr("height", "100%")
  .call(d3.behavior.zoom().on("zoom", function () {
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")

That's it!

Now you can add all SVG node to that g view port element.

There is a live example here:

Update for v4

For d3v4 it's even simpler, no more d3.behavior.zoom() behavior.

var svg ="body")
 .attr("width", "100%")
 .attr("height", "100%")
 .call(d3.zoom().on("zoom", function () {
    svg.attr("transform", d3.event.transform)

There is a live example here

Say Thanks

9 Responses
Add your response


I added .on("dblclick.zoom", null) just before the .append('g') to disable doubleclick zoom

over 1 year ago ·
Pprwgdyc normal

Oh boy, this is what I call simple, thanks buddy!

over 1 year ago ·

How to reset the zoomed graphic to its original scale?

over 1 year ago ·

you can do
svg.attr("transform", "translate(0,0) scale(1)");
But you'll also need to reset the d3.behavior.zoom. You need to modify a little the snippet to use a variable for the behaviour.
Let me know if it's clear enough. If not, I'll try to get 5 mn to make a new snippet.

over 1 year ago ·

This is awesome! Works like a charm. Is there any chance you can elaborate a bit more on how to do reset the d3.behavior.zoom for a reset button? Thanks!

over 1 year ago ·

Found the answer, thanks:

zoom.translate([0, 0]);
svg.transition().duration(500).attr('transform', 'translate(' + zoom.translate() + ') scale(' + zoom.scale() + ')')

over 1 year ago ·

Does anyone know how this would be written in v4? I know d3.behavior.zoom becomes d3.zoom but ' .attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")") ' is giving me trouble. Thanks!

over 1 year ago ·

Figured it out. Here's my code that works in D3 V4:

//Width and height
var w = 400,
h = 300;

// projection
var projection = d3.geoAlbersUsa()
.translate([w / 2, h / 2])

//Define default path generator
var path = d3.geoPath()

// Define Zoom Function Event Listener
function zoomFunction() {
var transform = d3.zoomTransform(this);"#map_g")
.attr("transform", "translate(" + transform.x + "," + transform.y + ") scale(" + transform.k + ")");

// Define Zoom Behavior
var zoom = d3.zoom()
.scaleExtent([0.2, 10])
.on("zoom", zoomFunction);

//Create SVG element
var svg ="#main")
.attr("width", w)
.attr("height", h)
.attr("id", "mapsvg")
.attr("id", "map

//Load in GeoJSON data
d3.json("json/us-states.json", function(json) {

//Bind data and create one path per GeoJSON feature
   .attr("d", path);


12 months ago ·

Thanks! Been scouring the web for a quick and easy solution (I'm a total noob with d3), but it was your post that helped me.

7 months ago ·