Mapbox-gl-js: Don't zoom the map if scroll is initiated outside of the map

Created on 10 Nov 2014  路  15Comments  路  Source: mapbox/mapbox-gl-js

The idea is to track scroll events on the document and disable scroll zooming if there was a scroll event outside of the map in the last N ms. cc @tatsvc

feature good first issue

Most helpful comment

Another approach I've seen on some websites is that mouse scroll is always page scroll, and zoom requires ctrl+scroll. When you scroll over the map, a message appears telling you to hold ctrl if you want to zoom. That worked pretty well.

All 15 comments

:-1: -- I don't think this actually addresses the use case of wanting to embed a "semi-static" map (working zoom buttons but no scroll-zooming) in a scrollable page. In that case, you don't want to zoom even if the scroll event is inside the map. The feature that is needed is just disabling scroll zoom entirely.

I reported this because there was a similar use case brought up in Leaflet (see https://github.com/Leaflet/Leaflet/issues/2076). It's very common to want a fully functional map (including zoom), but in a way that doesn't interfere with scrolling when user wants to scroll past the map.

it resulted in an immediate, massive usability improvement in my app.

Yeah, I just don't think "scroll event outside of the map in the last N ms" is a reliable indicator of "does/does not want to scroll past the map".

I can _really_ recommend trying a prototype with and without this.

It didn't sound like a great idea to me either, but I can't argue with how much it improves a map on a scrollable page.

We've done this in the past with stuff like deadsea. It's possible and actually works pretty well: the whole of deadsea is:

(function(context) {
    var deadsea = {};

    function isFamily(parent, child) {
        if (parent === child) return true;
         var node = child.parentNode;
         while (node !== null) {
             if (node === parent) {
                 return true;
             } else {
                 node = node.parentNode;
             }
         }
         return false;
    }

    deadsea.blockScrollInto = function(el) {
        var locked = true;
        // This is not compatible with IE.
        if (!window.addEventListener) return this;

        function handleMouseWheel(e) {
            if (!isFamily(el, e.target)) {
                locked = true;
            } else if (locked) {
                e.stopPropagation();
            }
        }

        window.addEventListener('mousewheel', handleMouseWheel, true);
        window.addEventListener('DOMMouseScroll', handleMouseWheel, true);

        el.addEventListener('mousemove', function mousemove(e) {
            locked = false;
        }, false);

        return this;
    };

    this.deadsea = deadsea;
})(this);

The effectiveness of this approach vanished when Mapbox switched embeds to iframes: there's no way to do a similar trick with iframes.

Closing as stale.

Pretty unfortunate that everyone has to work around this (or more likely, leave it and have a poor scrolling UX)

Oh, this would be great. I had a bunch of maps embedded in a long scrollable page (here), but it was virtually unusable, because it was so hard to scroll past them. I had to add a buffer to the sides so you could use those as a kind of footpath to avoid the map holes. :)

Any news on this one..?

Another approach I've seen on some websites is that mouse scroll is always page scroll, and zoom requires ctrl+scroll. When you scroll over the map, a message appears telling you to hold ctrl if you want to zoom. That worked pretty well.

I have a page where mouse scroll is always page scroll and opted for onscreen +/- buttons for zoom.

However the map still requires a "footpath" margin for use on a touch screen. That's valuable screen estate lost to otherwise superfluous margins and highly irritating UX.

Unless I'm missing something there doesn't appear to be a way to differentiate say 1 finger scrolls page vs 2 fingers together move map, 2 fingers opposing directions zooms.

Did anyone else find a solution to touch ?

Another approach I've seen on some websites is that mouse scroll is always page scroll, and zoom requires ctrl+scroll. When you scroll over the map, a message appears telling you to hold ctrl if you want to zoom. That worked pretty well.

锟硷考There's now a ticket for that #6884.

I did not address the problem of designing the necessary layer informing the user on using the CTRL key. I may add that later, after our designer comes up with something nice and our company allows it to be part of my PR. Until then, solutions are welcome!

Also the easiest way to make this work until PR is merged and not using our fork, is this:

document.querySelector('canvas.mapboxgl-canvas').addEventListener('wheel', (ev) => {
  if (ev.ctrlKey) return

  // You can have a layer on top of your map and trigger some CSS animation
  // to display it on scrolling attempt here
  ev.stopImmediatePropagation()
})

This will allow the document to scroll when scrolling without theCTRL key pressed.

I guess this is a bit late, but I'll add a solution for late visitors looking for possible answers.

Our scenario was that our maps can be embedded in a page as an iframe, or embedded as elements directly in the page. We do not know the nature of the parent page and have no control whatsoever of the environment.

How we solved the problem was to add onfocus and onblur events to the element containing the map.

<div id="map" onfocus="focusEvent" onblur="blurEvent"></div>

The onBlur and onFocus events will turn the scrollWheel property on and off.

In the main Map Script

// adds mouse scroll when the user clicks the map
focusEvent = () => { // or function onfocus() {
  map.scrollWheelZoom.enable();
};
// removes mouse scroll when the user clicks the map
blurEvent = () => {// or function onfocus() {
  map.scrollWheelZoom.disable();
}

Hope this helps anyone trying to achieve the same as us.

Happy mapping

I don't know what behaviour others are seeing, but for me if I start scrolling outside the map and continue scrolling through the map it will still only scroll the page and not zoom the map. If I stop scrolling and start again on the map it will zoom, but if I don't stop it will just scroll the page which is nice. I think this is alright because increasing that time any more would be too much in the other direction scrolling the page when I want to zoom the map.

Was this page helpful?
0 / 5 - 0 ratings