-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
loaded()
and on('load')
event do not work as expected
#6707
Comments
Thanks for describing this pain point @gmaclennan. You're right: I think adding a |
Thanks for the quick answer @anandthakker I think that would help this, along with perhaps update to the docs that cross-reference events with corresponding methods. I've realized that I am using Thanks for looking into this. I've been meaning to document the pain points I keep hitting every time for a while. |
I think mapbox-gl-js/src/style/style.js Lines 243 to 244 in a5a8dfe
(Confusingly,
|
Thanks. I am continuing to experiment with this, and hit another strange behavior: I was trying to get layers to fade in after the tiles have loaded for certain map views. I am doing this: if (map.areTilesLoaded()) doSomething()
else map.on('tiledata', doSomething) However |
I have been using some patterns for common map lifecycle events that I have found useful for projects I have written, these are the functions I'm currently using, they may be useful for others. These were not obvious for me from the docs, and are based on reading through the source code to try to understand the lifecycles, I'm not 100% sure they are correct. /**
* Call a function when the map's style has loaded. You can safely add and
* modify map layers within this function
*
* @param {mapboxgl.Map} map
* @param {function} fn
*/
function onMapStyleLoaded (map, fn) {
if (map.isStyleLoaded()) return process.nextTick(fn)
map.once('styledata', () => onMapStyleLoaded(map, fn))
}
/**
* Call a function when the map's tiles have loaded, i.e. most network activity
* is complete (although sprite and font loading may still be occurring)
*
* @param {mapboxgl.Map} map
* @param {function} fn
*/
function onMapTilesLoaded (map, fn) {
if (map.areTilesLoaded()) return process.nextTick(fn)
map.once('sourcedata', () => onMapTilesLoaded(map, fn))
}
/**
* Call a function when the map has finished rendering and transitions are
* complete
*
* @param {mapboxgl.Map} map
* @param {function} fn
*/
function onMapRenderComplete (map, fn) {
if (map.loaded()) return process.nextTick(fn)
map.once('render', () => onMapRenderComplete(map, fn))
} |
See also the long discussion in #6076. There definitely seems to be a mismatch between, on the one hand, the events, status functions and documentation, and on the other, what users expect and need in order to predictably manipulate the map state without triggering errors. |
Just want to add a very concrete demonstration that
See this demo: https://bl.ocks.org/stevage/raw/96066b4b8914ee40309260340db509eb/ Open the console. It does a count using The As far as I can tell, there is no event you can listen to that is fired after the first render is actually complete and it's safe to call |
I have also experienced that I am adding GeoJSON data to a map from a different component. Since it's possible that the data is ready before the map can receive it, or even exists, I'm polling the map object to see if it exists, and if The race condition blows up when isLoaded returns false, but the map is actually loaded because the data is not set directly, and the handler isn't called. One of the solutions mentioned above would help or adopting the jQuery idea that load handlers registered after the map is loaded are called immediately would also help. |
@gmaclennan Thanks for your suggestions above. I found I had to modify onMapTilesLoaded a bit more to get it to work for me:
So complicated! My use case here is a user selecting a boundary, then switching to a different dataset with equivalent boundaries. I need to wait for the new dataset to load, then identify the comparable boundary to select. This method above did eventually work...but yeah, it's very sub-optimal having to repeatedly poll |
I ran into another issue today. |
This problem is also causing issues with the
...resulting in Using mapbox-gl 0.54.0 |
Today I found that @gmaclennan's first version (onMapStyleLoaded) sometimes doesn't work. It fires twice, with I'm surprised this issue doesn't get higher priority from the devs. I am still finding this a major pain point in different projects. "Add data and layers at runtime" is a core use case for the library, and it is difficult to do reliably. |
Yes we've continued to hit bugs with not being able to do this reliably. I would love to see a solution, unfortunately this is all too deep within the code of mapbox-gl-js for me to even start a fix myself beyond workarounds. |
What about just polling
|
For anyone interested in a workaround: Take a look at mapbox/mapbox-gl-directions#111 Here, the fix described is using the internal |
I really do not mean to bump this, but I am looking for a list of mapbox events. I cannot find them in the docs. So far, what I am doing is using something like |
@CodeAmend All the publicly available events are listed in our docs. You can view all the map events starting here for example. |
Thanks man |
I have just run into this problem again, in Mapbox GL JS 3.0.1, with mapbox-gl-draw. An intermittent bug, where my code worked fine for a while...until it suddenly doesn't. You can see that mapbox-gl-draw uses exactly the pattern described above:
In my app, I'm adding the Draw object to the map after Super frustrating. |
Huh, I have just realised that an easy workaround in my case is to simply do add this:
|
mapbox-gl-js version: 0.45.0
Question
There are certain methods that you cannot call while the map is still loading, such as
map.addLayer()
. You can use themap.on('load')
event to know when it is safe to call these methods, however there is no corresponding method likemap.ready()
for knowing that it is safe to callmap.addLayer()
.map.loaded()
can also return false during other method calls, such asmap.setLayoutProperty()
, and you can safely callmap.addLayer()
whenmap.loaded()
returnsfalse
. Also ifmap.loaded()
returnsfalse
thenmap.on('load')
only works the first time, so you need to track the initial load state yourself.Every time I have tried to make a complex map with mapbox-gl I have hit some kind of frustrating bug that was related to loading state and these events. They have changed gradually over versions but they still don't work as expected.
It would be great if
mapbox-gl
could just track its ready state internally, so that callingmap.addLayer()
just worked as expected straight away. Either that or we need methods that correspond to load events. I want to do something like this:But this will only work the first time (
map.on('load')
only fires once), but sometimesmap.loaded()
will return false if the map is moving.Links to related documentation
The text was updated successfully, but these errors were encountered: