Zoom behaivour with key modifiers

287 views
Skip to first unread message

Michael Harris

unread,
Mar 10, 2016, 1:45:11 AM3/10/16
to d3-js
Hi,

Our application is using D3 to generate charts, and we use zoom behaviors to provide zooming and panning.

I'm getting complaints from users that when they are using their scroll wheel to scroll through one of our application's web pages, as soon as it scrolls to the point where their mouse is over a chart, then the scroll wheel stops scrolling the document and starts zooming that chart.

I was thinking of solving that by changing the behavior such that it only consumed wheel events while a modifier was pressed (eg. ctrl+scroll = zoom chart, scroll without ctrl is ignored and processed by the browser).

Looking at behaivour/zoom.js it does not look like that is currently supported, all mouse wheel events are consumed regardless of any modifiers, but it would be easy to add:

 1. Add a function to allow setting the desired modifiers that have to be pressed in order for wheel events to be processed

 2. In the mousewheeled() function, return immediately if an event occurs which does not match those modifiers (allowing the event to propagate upwards)

Of course if the modifiers are not set then it should behave as it does today.

So, my questions are: first, have I missed anything - is there some better way to do this without actually modifying D3?

Second - would such a feature be accepted if I did implement it?

Thanks for any feedback!

Regards
Mike

Luca Bonavita

unread,
Mar 10, 2016, 3:28:08 AM3/10/16
to d3...@googlegroups.com
Hi Mike,

you might activate the zoom after a certain amount of time the mouse entered the chart and disable the zoom again when the mouse leaves the chart, so that the user needs to express intention to use the chart by keeping the mouse over it for a bit, say half a second.

Have no time to test this out but I'd start from something like this:

var chartCanZoom = false
var delay = 500    // ms

var zoom = d3.behavior.zoom().on('zoom', zoomListener)

function zoomListener() {
    if (chartCanZoom) {
        // update the chart
    }
}

chartBackgroundElement
.on('mouseenter', function() {
    setTimeout(function() {
        chartCanZoom = true
    }, delay)
})
.on('mouseleave', function() {
    chartCanZoom = false
})


Regards,
Luca




--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
*************************** Disclaimer *****************************
The contents of this e-mail and any file transmitted with it are
confidential and intended solely for the individual or entity to
whom they are addressed. The content may also contain legal,
professional or other privileged information. If you received this
e-mail in error, please destroy it immediately. You should not copy
or use it for any purpose nor disclose its contents to any other
person. The views stated herein do not necessarily represent my
view. Please ensure you have adequate virus protection before you
open or detach any documents from this transmission. I am not
accepting any liability for viruses.
********************* End of Disclaimer ****************************

Michael Harris

unread,
Mar 10, 2016, 4:22:14 AM3/10/16
to d3...@googlegroups.com
Hi Luca

Interesting suggestion.  However,  the zoom behavior always stops the event from bubbling up,  so even if you were not over the chart for the prescribed time,  the normal scroll wheel action (scrolling the whole document ) would not occur, right?

Regards
Mike

You received this message because you are subscribed to a topic in the Google Groups "d3-js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/d3-js/LchLExbuk-0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to d3-js+un...@googlegroups.com.

Luca Bonavita

unread,
Mar 10, 2016, 5:01:09 AM3/10/16
to d3...@googlegroups.com
Hi Mike,

snap you're right, you need to disable the zoom completely.

Something like this should work:

var delay = 500
var zoom = d3.behavior.zoom().on('zoom', null)

function zoomListener() {

    // update the chart
}

chartBackgroundElement
.on('mouseenter', function() {
    setTimeout(function() {
        zoom.on('zoom', zoomListener)

    }, delay)
})
.on('mouseleave', function() {
    zoom.on('zoom', null)
})


Regards,
Luca


Luca Bonavita

unread,
Mar 10, 2016, 5:08:47 AM3/10/16
to d3...@googlegroups.com
Hi Mike,

I've just tried this on some local code and no, it doesn't work again: I'll see if I can find a solution debugging this on real code.

Regards,
Luca


Luca Bonavita

unread,
Mar 10, 2016, 5:43:30 AM3/10/16
to d3...@googlegroups.com
Hi Mike,

this works:

var delay = 500
var zoom = d3.behavior.zoom().on('zoom', zoomListener)


function zoomListener() {
    // update the chart
}

chartBackgroundElement
.on('mouseenter', function() {
    setTimeout(function(node) {
        d3.select(node).call(zoom)
    }, delay, this)

})
.on('mouseleave', function() {
    d3.select(this).on('.zoom', null)
})



Time permitting I'll put out a block with some real code of this.

Have a look at https://github.com/mbostock/d3/wiki/Zoom-Behavior#zoom, the part referring to 'zoom' namespace.

Regards,
Luca


Luca Bonavita

unread,
Mar 10, 2016, 10:35:39 AM3/10/16
to d3...@googlegroups.com
Hi Mike,

here's the block that shows the suggested approach: https://bl.ocks.org/mindrones/3e775233c1417caf7d7e

(here's the raw version: https://bl.ocks.org/mindrones/raw/3e775233c1417caf7d7e/)

Regards,
Luca


Michael Harris

unread,
Mar 10, 2016, 6:43:13 PM3/10/16
to d3-js
Hi Luca

Many thanks, I'll give it a try and also ask my stakeholders if they will accept the timer based approach. I think I may still have problems though, because I now have a similar issue with panning - they'd like me to add a feature that allows setting the zoom area by drawing a rectangle over the area of interest, which interferes with panning. I think I saw a block somewhere about controlling precedence of drag actions though.

Regards // Mike

Drew Winget

unread,
Mar 17, 2016, 12:35:30 PM3/17/16
to d3...@googlegroups.com
There's no reason this has to be activated with a timer. You can use the above approach for binding and unwinding the event but do so in response to a different event/flag.

To achieve your original intent of using a modifier key, you can set the flag or control an event binding from the callback or handler of a keydown/keyup sequence. Alternatively, you can use a library such as mousetrap or keymaster (both available on npm) to deal with the keypresses.


--
Drew Winget
Visualisation Engineer
Digital Library Systems and Services
Stanford, CA 94305


Reply all
Reply to author
Forward
0 new messages