mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.15k stars 2.22k forks source link

Map resize fires "movestart", "move", and "moveend" events. #6512

Open hughlomas opened 6 years ago

hughlomas commented 6 years ago

Mapboxgl, current version.

https://github.com/mapbox/mapbox-gl-js/blob/6997943681e50b6563f98f20887cf83c6e0ddfbf/src/ui/map.js#L428-L442

The resize function fires movestart, move, and moveend. This is nonsensical, during a resize the map has not moved. This is causing those event handlers to fire unnecessarily, and I don't see any way to distinguish the "source" of the event.

mlms13 commented 6 years ago

Indeed, if you have the map set to listen for window resizes (which I think is the default behavior), this causes many moveend events to fire repeatedly when the browser window is resized. Since I'm trying to load updated data when the user repositions the map, this is hitting my server with lots of garbage requests.

Is there an easy way to tell which move* events were triggered by the user vs which ones were programmatic?

jovanjay commented 6 years ago

@mlms13 I have a hacky solution but not sure if it works for you, but there is actually a public variable called "_moving" which will be true if the map is being dragged around. If map resize is being called this variable remains false.

mapobj.on('move', function(){ if(mapobject._moving){ console.log('has moved'); } })

mlms13 commented 6 years ago

Thanks @jovanjay, I'll have to play around with this.

A closely related problem I'm running into:

johnfrancisgit commented 5 years ago

Having the same issue.... :(

nathanredblur commented 5 years ago

no solution fo this then?

ctaylor4874 commented 5 years ago

Any solutions for this? I'm having the same issue

gzurbach commented 4 years ago

I've been banging my head on this issue for hours, at least now I know what's causing it. Did anyone found an elegant solution to this? Any way to know what triggered the moveend event?

EDIT: I was able to solve my issue by checking the originalEvent.type property. It does not say if the resize originates from a user interaction specifically but in my case it was good enough. Hope this helps!

this.map.on('moveend', (eventData)=> {
  let sendAction = true;
  if (eventData && eventData.originalEvent && eventData.originalEvent.type === 'resize') {
    sendAction = false;
  }

  if (sendAction) {
    // do the thing
  }
}
mlms13 commented 4 years ago

Not sure if my solution counts as elegant... :)

When you set up the map, you can configure a trackResize property. It's true by default, but I set it to false. Then, I added my own resize handler to redraw the map, passing along extra metadata that I can check for elsewhere:

window.addEventListener('resize', () => myMap.resize({ programmatic: true }));

That {programmatic: true} flag gets passed into all of the other events triggered by resize, so in my handlers for e.g. map.on("moveend", evt => ...), I can check for evt.programmatic and handle the event differently. This is very similar to your check for originalEvent.type, but it offers me a little extra control (e.g. I can pass a programmatic flag from other non-user-triggered move events, which allows me to only re-fetch data when the user would expect it).

So again... elegant? Hardly. But it works well enough for me to only do "moveend" things when the map has actually been moved.

olso commented 4 years ago

You can use dragstart

kolnogorov commented 4 years ago

Still no working solution out of the box for this? Oh, my.

321ckatz123 commented 3 years ago

For my use case of updating the source data when the user moves the map, changing from moveend to dragend solved the problem and stopped the numerous calls being made. This is clearly a workaround, but it did solve the problem for me.