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 = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.behavior.zoom().on("zoom", function () {
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))
.append("g")
That's it!
Now you can add all SVG node to that g
view port element.
There is a live example here: http://bl.ocks.org/sgruhier/1d692762f8328a2c9957
Update for v4
For d3v4 it's even simpler, no more d3.behavior.zoom()
behavior.
var svg = d3.select("body")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g")
There is a live example here https://bl.ocks.org/sgruhier/50990c01fe5b6993e82b8994951e23d0
Written by Sébastien Gruhier
Related protips
11 Responses
I added .on("dblclick.zoom", null) just before the .append('g') to disable doubleclick zoom
Oh boy, this is what I call simple, thanks buddy!
How to reset the zoomed graphic to its original scale?
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.
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!
Found the answer, thanks:
zoom.scale(1);
zoom.translate([0, 0]);
svg.transition().duration(500).attr('transform', 'translate(' + zoom.translate() + ') scale(' + zoom.scale() + ')')
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!
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])
.scale([500]);
//Define default path generator
var path = d3.geoPath()
.projection(projection);
// Define Zoom Function Event Listener
function zoomFunction() {
var transform = d3.zoomTransform(this);
d3.select("#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 = d3.select("#main")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("id", "mapsvg")
.append("g")
.attr("id", "mapg")
.call(zoom);
//Load in GeoJSON data
d3.json("json/us-states.json", function(json) {
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path);
});
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.
Thanks!
How do I use this to refer to an external .svg file - e.g. picture.svg?