I'm trying to display a map of a single state, with zooming and panning constrained to the boundaries of the state. It's mostly working, except for the panning constraint when the state path is scaled to fit a smaller container. I think this es down to me not understanding what arguments to use for zoom.translateExtent
(although I'm very new to this, so it could be something else).
Live example on bl.ocks, with links to prior art.
One notable thing is that I'm using a null projection for d3.geoPath
, because I used ogr2ogr
to generate a shapefile in projected coordinates for each state. That's why I used a zoom transform to fit the map to its container.
I'm trying to display a map of a single state, with zooming and panning constrained to the boundaries of the state. It's mostly working, except for the panning constraint when the state path is scaled to fit a smaller container. I think this es down to me not understanding what arguments to use for zoom.translateExtent
(although I'm very new to this, so it could be something else).
Live example on bl.ocks, with links to prior art.
One notable thing is that I'm using a null projection for d3.geoPath
, because I used ogr2ogr
to generate a shapefile in projected coordinates for each state. That's why I used a zoom transform to fit the map to its container.
- The ask here is a little confusing. Could you elaborate on the issue you are having? I am not seeing the issue you are talking about! – Tekill Commented Jul 27, 2016 at 12:31
-
Sorry, I've updated my example to be more clear. Basically, when I transform the state to fit a smaller container, the drag-to-pan functionality breaks. I think there's something wrong with the way I'm using the transform calculated by
zoomBounds
in conjunction withtranslateExtent
. If I remove thetranslateExtent
line, the panning is smooth, but not constrained to the container. – bhrutledge Commented Jul 31, 2016 at 14:59
2 Answers
Reset to default 5@McGiogen's solution is almost correct but misses that MIN
needs to vary depending on the zoom scale factor transform.k
.
I drew a diagram to see how I needed to constrain my svg to always be contained inside the zoomed view (depicted in my drawing as the LARGER of the boxes, only a portion of which is visible to the user):
(since the constraint x+kw >= w
is equivalent to x >= (1-k)w
, with a similar argument for y
)
thus assuming your svg
container size [w, h]
:
function zoomed() {
var t = d3.event.transform;
t.x = d3.min([t.x, 0]);
t.y = d3.min([t.y, 0]);
t.x = d3.max([t.x, (1-t.k) * w]);
t.y = d3.max([t.y, (1-t.k) * h]);
svg.attr("transform", t);
}
I'm facing the same problem today and I've done some tests.
I've noticed that it's the same weird behaviour happening when you have a translateExtent box smaller than the content's elements.
In your (and mine) code the same behaviour is triggered by zooming out: it doesn't matter if you have the translateExtent box correctly set with no zoom, if you zoom out the box is reduced at higher rate than the elements and at some point you will have translateExtent box smaller than the content (and the weird behaviour).
I temporary solved this as said here D3 pan+ zoom constraints
var MIN = {x: 0, y: -500}, //top-left corner
MAX = {x: 2000, y: 500}; //bottom-right corner
function zoomed() {
var transform = d3.event.transform;
// limiting tranformation by MIN and MAX bounds
transform.x = d3.max([transform.x, MIN.x]);
transform.y = d3.max([transform.y, MIN.y]);
transform.x = d3.min([transform.x, MAX.x]);
transform.y = d3.min([transform.y, MAX.y]);
container.attr("transform", transform);
}
I'm still a d3 newbie but I think that this is a bug in translateExtent code.