I've got this d3 js map. I've tried to make such a simple thing as zoom and pan and just stalled. Now only dots zooms (I use v4). How to 'synchronize' zoom and pan of dots and map svg?
How to set limits of zoom and pan in d3 v4? I want it to be like this
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.style("border","none")
.style("background-color", "none")
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g");
The circles scale but the paths do not because of how you append them. First, let's see how you apply the zoom:
var svg = d3.select("body")
.append("svg")
...
.call(d3.zoom().on("zoom", function () {
svg.attr("transform", d3.event.transform)
}))
.append("g"); // returns a selection of a newly appended g element
So the selection svg
is actually a g
element. While zoom is called on the svg element (not svg selection) it modifies the svg selection (which is actually holds a g): svg.attr(("transform"...
.
When you append your paths you use var map = d3.select("svg").insert(...
and create a new g
to hold the paths. But - this g
is not in or a child of the selection svg
- so it is not updated: d3.select("svg") != svg
in this case. Instead, use:
var map = svg.insert(... // we insert into the svg selection which holds a g
This way we are inserting elements into the parent g
that is updated each zoom.
While this really is a second question, the solution is simple enough. A d3.zoom() behavior can be constrained by both scale and translate:
d3.zoom().scaleExtent([1,4]) // limit scale to full size or 4x size.
.translateExtent([[0,0],[width,height]]) // limit pan to original SVG dimensions
zoom.translateExtent([p1,p2])
takes two points, upper left and lower right. We can constrain based on these dimensions if your features don't extend past the SVG bounds when initially loaded with a scale of 1.
Here's an updated bin.