MapBox event when all Tiles are loaded - javascript

I'm using Mapbox GL JS API to manipulate a Mapbox map. Right before I upload my result (which is a canvas.toDataURL) to the server through HTTP I need to resize my map (bigger resolution) and then use fitbounds to get back to the original points. After fit bounds fires, it takes the map a while to load all new tiles in. Only after this can I actually perform the upload. Right now though, I don't know if there's an event that's capable of telling me if all tiles are loaded.
I've tried all possible load functions and events in the API. There's a few issues on the GITHUB project but they're now at least a year old and there's been no update. Halfway through 2015 they started talking about adding an Idle event, but I can't seem to find any new documentation of it anywhere.
Has anyone found a way to make the code wait for the map to load? Or has any information regarding an update on this feature?
I doubt it matters much, but I'm working in an angular.js app.

We just added a Map#areTilesLoaded check which sounds like what you're looking for. That should go out in the next release (v0.37.0). In the meantime, the following should work.
map.on('sourcedata', (e)=> {
if (map.loaded()) {
// all tiles are loaded
// turn off sourcedata listener if its no longer needed
map.off('sourcedata');
}
});

Related

How to best tie into a webapp's mapbox-gl update code?

Background
I'm writing a browser extension which paints over the map of komoot.com/plan.
Currently I do this by placing a canvas on top of the existing canvas.
This works well but it is static and does not yet react to when the user moves the map around or zooms into it or the website focusses a particular location on the map.
Question
How do I best tie into this event loop of map updates?
Approaches considered
I could mimic / reimplement how komoot processes user input, but this sounds fragile and unreliable and messy. I would do this by adding listeners for mouse button events and cursor movement, etc.
The page's URL contains the lat and long coordinates together with the zoom level, e.g., https://www.komoot.com/plan/#49.9535480,5.3956956,11.345z. It changes after the map has changed. I assume there's a way to be notified of changes in the URL. If so I could then dynamically update my canvas.
This would still require some level of imitation of the page's internals. However, considerably less so than option 1.
Doing so I could only update my canvas after the animation is finished. Not a deal breaker but ideally I'd want to update it frame by frame together with the map itself for a more pleasing user experience.
Additional Details
Komoot seems to be using mapbox-gl
It's a Manifest 2 Content Script extension
This is my first browser extension ever
I'm writing this in Scala.js using this excellent template
Don't let this keep you from posting javascript solutions or pointing me to javascript documentation!
Screenshot
You don't seem to have mentioned the obvious way: use the move event:
map.on('move',e => {...
// get center with map.getCenter()
});
But it's not really clear exactly what you're trying to do, so hard to advise more specifically.

Use mapbox for rendering inside pixi-js or any other webgl/canvas framework?

I love the styling options provided by mapbox and need to know if there is any way I can use their map api for a game I am writing.
I dont think I can make any use of a fully finished solution that just loads the map into a container element (mapbox-gl-js) but rather would need image data etc. to use myself in a different engine.
Is this even possible with mapbox? How would I do it?
Turns out I was looking in the wrong place. Mapbox has its "static" api which allows to fetch the tiles as images directly without rendering it interactively.
So for anyone looking to use mapbox customly then make sure too check out their static api over at: https://www.mapbox.com/api-documentation/#static

How do I prevent a dynamicMapLayer from refreshing on every zoom or pan of the map?

I'm using the leaflet L.esri.dynamicMapLayer to display a large amount of polylines on the map, and the export request to ArcGIS Server to draw them can take a while. If the user quickly makes several zooms or pans, I can end up with a bunch of pending export requests, which also blocks other requests to ArcGIS Server. All those export requests except the last are useless.
For other client side layers, I'm already controlling the refresh by making sure the user has stopped zooming or panning for at least 2 second before refreshing the layers myself. How can I do the same for the dynamicMapLayer, can I pause or stop the automatic refresh and decide myself when I want the export request to be made?
Note that we cannot use tiles for better performance, because of other reasons the layer must stay dynamic.
How do I prevent a dynamicMapLayer from refreshing on every zoom or pan of the map?
You can not. It is designed that way.
Unless the esri folks redesign that to make a subclass of L.GridLayer instead of L.ImageOverlay, there's hardly any way around it.
I'm already controlling the refresh by making sure the user has stopped zooming or panning for at least 2 second before refreshing the layers myself. How can I do the same for the dynamicMapLayer?
With a horrible, ugly hack. Overwrite the private L.Esri.DynamicMapLayer._update method so that it becomes a decorator over the previous method, e.g. something like:
(function() {
var previousProto = L.Esri.DynamicMapLayer.prototype;
L.Esri.DynamicMapLayer.include({
_update: function(){
throttle(previousProto._update, 2000);
}
});
})();
It's ugly, it's against most good coding practices (overwriting private methods, eeeew), and it might break.
Note that we cannot use tiles for better performance, because of other reasons the layer must stay dynamic.
I disagree. "tiles" doesn't mean "static". You can easily apply cache-busting, or use a time dimension, or send all data to the client and let it slice it into vector tiles for quick rendering, or use something fancier like Carto(DB)'s Torque.
The fact that your Esri tools don't allow you to readily create different sets of tiles, or do not allow for tiled access of changing resources, or do not allow for triggering client-side data invalidations, doesn't mean that it cannot be accomplished.

Better solution for loading data onto a map

I'd like to ask if anyone knows a good solution to my problem.
I have a Rails project with a Bing map, where I need to load about 20000 pushpins.
The problem that I have is the speed of my data load. I've tried to optimize the load time by only including required fields for records (id, latitude, longitude). It made some difference but still was not a good load time.
Next thing that I've done - started loading records in batches (a couple hundred at a time). As a result, pushpins started showing up almost instantly, but again, it took a really long time to fully load the data set.
I'd really appreciate any suggestions about a better way to load the data.
Thanks in advance!
You have several solutions to achieve what you want to do but the main question would be, do you really need to display the 20k pushpins onto the map control and display them all at once? I'm pretty sure it will lack of readibility and adding to performance cost, you might consider dynamicaly restrict the number of elements that will be displayed and load only those who can really be seen.
1: Client-side clustering
Using your own implementation or the Bing Maps Module available here: http://bingmapsv7modules.codeplex.com/wikipage?title=Client%20Side%20Clustering, you can create cluster to ease the data manipulation and rendering of the pushpins.
2: Dynamicaly load (Server-side clipping and clustering)
Each time you fire 'onviewchanged', you can make an AJAX call to refresh the information and clear the previously added pin. Also, if you are a zoom level or in a specific area where you have to display every pushpin, you can create cluster of pushpins so you will display only one pushpin that says 'there are 12 pins in here'. I'm sure you get the point.
3: Composing dynamic tile on server-side or on client-side
If you need to display everything, the latest solution would be to draw things on dynamical tiles on server-side or on client-side depending on your use case, see: http://www.web-maps.com/gisblog/?p=1605

Can I trap rendering events with google map Api

I try to draw a very large dataset on google map (2500+ rectangles). The rendering of the rectangles take more than 5 secs. The whole page just stuck for the 5 secs, so I am thinking about adding a loading indicator or progress bar during the rendering.
To do this, I need to trap events of rending (start,finish rendering).
I checked the google maps Api documentation, did not find anything useful. Just what to know whether there is some work around or something I miss in the api doc that can help me to trap rendering events.
As of Google Maps v3.14 the answer is no. There's no such event to listen for in the API. If you dug through the code long enough you might be able to find a hack, but given that you're in control of the rectangles you're drawing and you have a count of them, why not iterate the progress bar as you add them? Individually they will render very quickly so whether you iterate the progress before or after each is added to the map should make no difference to the user, despite the fact that it feels like the wrong order to the developer.
This gives an overview of all the events in GMapsV3 http://gmaps-samples-v3.googlecode.com/svn/trunk/map_events/map_events.html
Check if the events you need are there.

Categories