I am searching for a possibility to temporarily disable the zooming functionality provided by the d3 library. I tried to save the cave the current scale/translation values when the zooming is deactivated and set the zoom/translate-values when the zooming is active again. Unfortunately this will not work.
Here is a code example I created :
var savedTranslation = null;
var savedScale = null;
var body = d3.select("body");
var svg = body.append("svg");
var svgContainer = svg.append("svg:g");
var circle = svgContainer.append("svg:circle")
.attr('cx', 100)
.attr('cy', 100)
.attr('r',30)
.attr('fill', 'red');
circle.on('click', clickFn);
function clickFn(){
if (circle.attr('fill') === 'red'){
circle.attr('fill','blue')
}
else if (circle.attr('fill') === 'blue'){
circle.attr('fill','red')
}
};
svg.call(zoom = d3.behavior.zoom().on('zoom', redrawOnZoom)).on('dblclick.zoom', null);
function redrawOnZoom(){
if (circle.attr('fill') === 'red'){
if (savedScale !== null){
zoom.scale(savedScale)
savedScale = null
}
if (savedTranslation !== null){
zoom.translate(savedTranslation)
savedTranslation = null
}
// the actual "zooming"
svgContainer.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.scale + ')');
}
else {
// save the current scales
savedScale = zoom.scale()
savedTranslation = zoom.translate()
}
};
Here is a working jsfiddle example.
EDIT:
The false behavior can be reproduced by following steps :
- Click on the circle, the color changes to blue,zooming is not working
- Use mouse wheel IN ONE DIRECTION several times as if you would be zooming (e.g. zoom in)
- Click again on the circle, the color chnages to red, zoom is re-enabled
- Use mouse wheel, the circle will be huge/tiny
I wanted to catch up on this as I found a solution! Trick is to reset scale and translate in the zoomstart- and zoomend-events as well.
The way I would implement this is with a global flag that tells you whether zooming is enabled or not. Then you simply need to check whether this flag is set in the function that handles the zoom. If it is, the function does nothing.
The easiest way I've found is to simply disable all the
.zoom
events on the selection. You'll have to re-callzoom
to enable the behavior again.jsfiddle
I have been struggling with the same problem. And, I have found a solution that saves zoom and translation without the jumpiness that you see with the current solution.
The main change is to perform the saving/updating of zoom and translate in the "click" function. And so that a reference to the zoom function is available, the click must be set after the zoom behavior. The solution looks like this. The same boilerplate from your problem:
Then the zoom function, without managing the saved scale and translate:
Finally, attach the click behavior below, with the saving and setting of scale and translation:
Here is a working version: http://jsfiddle.net/cb3Zm/1/.
However, the click event still happens when a drag occurs, and that doesn't seem ideal, but I haven't been able to fix it yet.
Yabba Dabba Doo!
Ok, the problem was in the
part. The values were called on every event, not only once after the circle changed its color. So the solution was:
and now IT WORKS ! Updated jsFiddle here.
See the updated fiddle: http://jsfiddle.net/prayerslayer/La8PR/1/
There I reassign an empty zoom behavior in the click handler.
I suppose there is a better solution as mine probably introduces memory leaks.
The advantage over a global
doZoom
flag is that you don't have to save and check scale and translation values because the zoom behavior continues to work (e.g. settingd3.event.scale
) even though you're not altering the view.