Reputation: 1003
I have a zoom event handler on my tree graph like so:
d3.select("#"+canvasId+" svg")
.call(d3.behavior.zoom()
.scaleExtent([0.05, 5])
.on("zoom", zoom));
Which calls the zoom function which handles the translation bounding logic:
function zoom() {
console.log(d3.event.translate[0]);
var wcanvas = $("#"+canvasId+" svg").width();
var hcanvas = $("#"+canvasId+" svg").height();
var displayedWidth = w*scale;
var scale = d3.event.scale;
var h = d3.select("#"+canvasId+" svg g").node().getBBox().height*scale;
var w = d3.select("#"+canvasId+" svg g").node().getBBox().width*scale;
var padding = 100;
var translation = d3.event.translate;
var tbound = -(h-hcanvas)-padding;
var bbound = padding;
var lbound = -(w-wcanvas)-padding;
var rbound = padding;
// limit translation to thresholds
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
console.log("Width: "+w*scale+" || Height: "+h*scale+" /// "+"Left: "+translation[0]+" || Top: "+translation[1]);
d3.select("#"+canvasId+" svg g")
.attr("transform", "translate(" + translation + ")" +" scale(" + scale + ")");
console.log(d3.select("#"+canvasId+" svg g")[0]);
}
However, translations beyond the bounds cause the d3.event.translate values to increase. The result is that even if the translation is not causing the graph to move as it has reached its limit for translation, the value for the translation within successive events can continue to increase.
The result is that say I drag the graph far to the left, even though it will stop moving past a certain point, because the value within the events continues to increase, I would then have to drag it a long way back right before it actually begins to move right again.
Is there a good way to prevent this behaviour?
Upvotes: 2
Views: 1581
Reputation: 1003
Okay I worked it out. The trick is to set the translation for the d3.behaviour.zoom so that successive zoom pans start at the bounded translation rather than with the additional panning that didn't actually give any movement.
To do this, we declare the zoom behaviour as a separate variable and add it to our zoomable element:
var zoomBehaviour = d3.behavior.zoom()
.scaleExtent([0.05, 5])
.on("zoom", zoom)
d3.select("#"+canvasId+" svg")
.call(zoomBehaviour);
Then we set the translation of this zoomBehaviour to our bounded translation in the zoom function:
function zoom() {
...
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
zoomBehaviour.translate(translation);
d3.select("#"+canvasId+" svg g")
.attr("transform", "translate(" + translation + ")" +" scale(" + scale + ")");
}
Upvotes: 4