Tilo Neumann
Tilo Neumann

Reputation: 21

How to prevent with mapbox gl js, that a mouse wheel interaction stops a fitBounds() animation?

I add some marker to a mapbox map and let the fitBounds() method from geojson-extent.js adjust the map position and zoom.

map.fitBounds( geojsonExtent(geojson), {
    padding: {top: 200, bottom:30, left: 30, right: 30}
});

The animation duration is set by default to five seconds. When the user do a mouse wheel interaction in this time over the map, the animation stops. No problem: The zoom stops the animation. But how can I prevent this?

I tried a lot of solutions:

1. disable the zoom

map['scrollZoom'].disable(); 

User can't scroll the map by mouse wheel, but animation still stops.

2. catch the wheel event

map.on('wheel', function(e) {
    e.preventDefault();
});

User can't scroll the map by mouse wheel, but animation still stops.

3. disable user interaction completely

var map = new mapboxgl.Map({
    interactive: false
});

Cool, animation is not being interrupted any more, but now the user can't pan the map. I found no solution to reset this property on run time or add navigation elements for panning.

4. set animation to important

map.fitBounds( geojsonExtent(geojson), {
    essential: true,
    padding: {top: 200, bottom:30, left: 30, right: 30}
});

No effect.

5. disable animation

map.fitBounds( geojsonExtent(geojson), {
    animate: false,
    padding: {top: 200, bottom:30, left: 30, right: 30}
});

This works, but it's a kind of workaround. I like to keep the animation.

6. add an overlay to block the user interaction

map.on('movestart', function(e){
    $("#map-box").append('<div class="block-interactions"></div>');
});
map.on('moveend', function(e){
    $("#map-box .block-interactions").remove();
});
.block-interactions {
    position: absolute;
    width: 100%;
    height: 535px; /* map height */
}

This is my current solution and it works, but feels like a bad hack and is still a workaround.

So, do you have an other idea to prevent the animation being interrupted? At best with mapbox methods.

Thank you, for your help!

Upvotes: 2

Views: 2160

Answers (1)

Nikolas Stevenson-Molnar
Nikolas Stevenson-Molnar

Reputation: 4710

You can disable interaction before calling fitBounds and then re-enable it in response to moveend and zoomend events.

// define map here...

function disableInteraction() {
    map.scrollZoom.disable()
}

function enableInteraction() {
    map.scrollZoom.enable()
}

map.on('moveend', function() {
    enableInteraction()
})

map.on('zoomend', function() {
    enableInteraction()
})

// The next two lines should go wherever you want to invoke `fitBounds`
disableInteraction()
map.fitBounds(/* ... */)

You can modify disableInteraction and enableInteraction if you want to disable other forms of interaction besides scroll zoom. For example, to disable everything:

function disableInteraction() {
    map.scrollZoom.disable()
    map.boxZoom.enable()
    map.dragRotate.enable()
    map.dragPan.enable()
    map.keyboard.enable()
    map.doubleClickZoom.enable()
    map.touchZoomRotate.enable()
}

Upvotes: 1

Related Questions