Recommended way to switch tile urls in mapbox-gl-js
Asked Answered
N

3

11

Situation

We render a raster layer to the map. The layer's source has an initial tile-url. Now we want to change the tile-url of the source and trigger a reload for the new tiles. E.g. we have tiles for different points in time and we want to step through the different time steps.

What can be done in [email protected]

map.addSource('tile-source', {...});
map.addLayer('tile-layer', {source: 'tile-source', ...});

// react to a button click or what ever to trigger tile url change
...
const source = map.getSource('tile-source');
source.tiles = ['new-tile-url'];
source._pyramid.reload();

This works fine. But, of course, using private methods is bad practice; see the reason below:

What can be done with the current version from github (Latest commit b155118, 2016-07-28)

// init map, add layer, add source, like above
const source = map.getSource('tile-source');
source.tiles = ['new-tile-url'];

map.styles.sources['tile-source'].reload();

It has to be done this way, because the former TilePyramid has been refactored to a SourceCache. Here we are calling reload() on the SourceCache not the RasterTileSource. It seems that we don't have to use any private methods anymore, though this still looks like undocumented API, which may break in future versions.

Also there seems to be an issue with a memory leak when calling reload(): https://github.com/mapbox/mapbox-gl-js/issues/2266

Additionally the cache gets cleared when calling reload(). Which for now doesn't seem to be an issue.

// This yields a `RasterTileSource` instance
map.getSource('tile-source'); 

// This yields a `SourceCache` instance
map.styles.sources['tile-source'];

// What's really confusing too, at least namingwise
map.getStyle(); // <-- Yields the maps (visual) style

The SourceCache has the RasterTileSource instance as a private _source field.

Question

What is the recommended way to do something like this? Is this a feature being worked on? Is there an explanation why this isn't a feature (yet) or never will be?

Navarra answered 28/7, 2016 at 8:46 Comment(1)
If your goal is to show different tiles one after the other, why not keep all the sources, and just play with the "visibility" property of the layers ?Boaz
W
2

Mapbox GL JS v2.13.0 released on 22 Feb 2023 Add methods for changing a raster tile source dynamically (e.g. setTiles, setUrl). (#12352)

So now you can update a raster source without remove layers and sources.

Waynewayolle answered 23/2, 2023 at 15:53 Comment(0)
H
8

It sounds like you're trying to change the URL of a raster source. The proper way to do this in GL JS is to remove the source and then add a new source with the same id and the new url.

map.addSource('tile-source', {...});
map.addLayer('tile-layer', {source: 'tile-source', ...});

// react to a button click or what ever to trigger tile url change
...
map.removeSource('tile-source');
map.addSource('tile-source', {tiles: ['new-tile-url'], ...});
Haff answered 4/8, 2016 at 18:28 Comment(3)
Thanks, we will try that.Navarra
I often see a source already exists error when doing this. I wish there were a setter like source.setTiles(['https://...']), it gels better with the source.setData for GeoJSON layers.Katabolism
You may see "source already exists" error when you think you removed source, but its not, because some layer uses it. Make sure there is not layers that use your source and it will be removed by map.removeSourceMudslinger
Z
5

Here is another way of changing the Mapbox GL JS Layer URL without removing, and adding the Source and Layer.

// Set the tile URL to a cache-busting URL (to circumvent browser caching behavior):
map.getSource('source-id').tiles = [ `http://some.url/{z}/{x}/{y}.pbf?dt=${Date.now()}` ]

// Remove the tiles for a particular source
map.style.sourceCaches['source-id'].clearTiles()

// Load the new tiles for the current viewport (map.transform -> viewport)
map.style.sourceCaches['source-id'].update(map.transform)

// Force a repaint, so that the map will be repainted without you having to touch the map
map.triggerRepaint()

I have figured out a solution. instead of sourceCache try _sourceCache function and type 'other' before your id.

map.style._sourceCaches['other:wms-source'].clearTiles();
map.style._sourceCaches['other:wms-source'].update(map.transform)

https://github.com/mapbox/mapbox-gl-js/issues/2941#issuecomment-518631078

Zeeba answered 18/7, 2021 at 9:11 Comment(0)
W
2

Mapbox GL JS v2.13.0 released on 22 Feb 2023 Add methods for changing a raster tile source dynamically (e.g. setTiles, setUrl). (#12352)

So now you can update a raster source without remove layers and sources.

Waynewayolle answered 23/2, 2023 at 15:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.