elachell
elachell

Reputation: 2687

How to disable pan for d3.behavior.zoom?

This question looks quite similar to this one, but I am still not able to figure out whether it is possible to use d3.behavior.zoom but without the pan ability. In other words I just want to zoom-in/out using the wheel only.

The reason for this is that I want to be able to brush on the "zoomable" area.

Thanks!

Upvotes: 30

Views: 16725

Answers (3)

seliopou
seliopou

Reputation: 2916

Say you've defined a zoom behavior:

var zoom = d3.behavior.zoom().on('zoom', update);

When you apply the zoom behavior to a selection, you can unregister the event listeners that it uses internally to detect and respond to certain interactions. In your case, you'd want to do something like this:

selection.call(zoom)
    .on("mousedown.zoom", null)
    .on("touchstart.zoom", null)
    .on("touchmove.zoom", null)
    .on("touchend.zoom", null);

I'm not sure you want to remove the touch events. Doing so might eliminate double tap zooming. You should experiment with those.

Upvotes: 48

sergeyz
sergeyz

Reputation: 1337

One solution that I found was to stick a rect element in front of the zoom-enabled element (they must be siblings) and set its fill to 'transparent', when I wanted to disable zoom interaction or to 'none', when I wanted to enable zoom interaction. It looked something like this:

if (chart._disableZoom) {
    var rootPanel = d3.select('.rootPanel'); // this is the parent of the element that can be zoomed and panned
    if (!rootPanel.select('.stopEventPanel').node()) { // create panel if it doesn't exist yet
       //.stopEventPanel is appended next to the zoom-enabled element
        rootPanel.append('rect').attr('class', 'stopEventPanel').attr('width', renderConfig.width).attr('height', renderConfig.height).attr('fill', 'transparent');
    } else { // disable zoom and pan
        rootPanel.select('.stopEventPanel').attr('fill', 'transparent');
    }
} else { // enable zoom and pan
    d3.select('.rootPanel').select('.stopEventPanel').attr('fill', 'none');
}

Upvotes: 1

elachell
elachell

Reputation: 2687

I guess it would be good sharing the workaround I found to deal with this problem. What I did is to use the listener on the start of the brush to "deactivate" the zoom:

zoom.on("zoom",null);
selection.call(zoom);

and activate it again on the brushend event.

There is one more trick to take into account and comes from the fact that it is important to save the scale and transition values of the last valid zoom interaction, so that you use those values when activating the brush on the brushend event like this

zoom.scale(lastEventScale).translate(lastEventTranslate).on("zoom",drawZoom);
selection.call(scatterZoom);

I would love hearing other more "elegant" solutions to this problem.

Upvotes: 4

Related Questions