37

I'm building a mapping web application using Mapbox-GL. It has a lot of cool features. I've set up the buttons to switch base maps (ie. satellite, terrain, etc) following the example on the Mapbox website.

The problem that I am having is that when I change the style it removes my polygons that are loaded as layers and reloads the map. I load in polygons from a Mongo database as layers based on user queries. I want to be able to change the base map and keep those layers.

Is there a way to change the style without reloading the map, or at least not droping the layers?

Here is my code for the switcher, its the same as the example but I added a condition for a custom style:

 var layerList = document.getElementById('menu');
    var inputs = layerList.getElementsByTagName('input');

    function switchLayer(layer) {
        var layerId = layer.target.id;
        if (layerId === 'outdoors') {
            map.setStyle('/outdoors-v8.json');
        } else {
        map.setStyle('mapbox://styles/mapbox/' + layerId + '-v8');
        }
    }

    for (var i = 0; i < inputs.length; i++) {
        inputs[i].onclick = switchLayer;
    }
Gold Masta
  • 695
  • 1
  • 10
  • 22

3 Answers3

30

Here's an example demonstrating that: http://bl.ocks.org/tristen/0c0ed34e210a04e89984

Unlike a mapping library like Leaftlet, Mapbox GL JS doesn't have a concept of "basemap" vs "other layers." All layers are part of the same entity: the style. So you need to keep some state of the data layer around and call its source/addLayer on each change.

tristen
  • 4,605
  • 4
  • 24
  • 19
  • 6
    Awesome! Thanks for the help @tristen. I was hoping that you could just swap the basemap, but Mapbox-GL is a bit different. I used your example for inspiration. Basically I had to save my loaded data to a variable and reload it using the `map.on('style.load' ...` function. It works pretty well. – Gold Masta Mar 23 '16 at 05:12
  • Thank you @tristen for the example and explanation. – bkowshik Jun 03 '16 at 12:31
  • Thanks @tristen. Any tips on how to do this for vector tiles coming from a tiling server (e.g. localhost/{z}/{x}/{y}.pbf)? geojson can be stored in a variable but if you have a lot of data and only want to show the current bounding box's vector tiles, I'm unsure how to persist the same data... – jondelmil Sep 25 '16 at 16:58
  • @jondelmil sounds like a different question? See https://www.mapbox.com/mapbox-gl-js/example/third-party/ for adding third party vector data to a map. The only thing this example demonstrates is swapping the base layer using `setStyle`. – tristen Oct 06 '16 at 13:48
  • @paolov the token under `mapboxgl.accessToken` has been disposed. The example should work by copying the code and providing your own access token! – tristen Oct 09 '17 at 16:46
9

Maybe I am late, but just for the record:

  • style.load is not part of the public API
  • use map.on('styledata') to monitor the style change

Please reference:

Yumin Gui
  • 389
  • 3
  • 9
  • 2
    this is the correct answer for anyone here in 2020. – jclark754 Aug 30 '20 at 01:53
  • However, 'styledata' will fire multiple times, while 'style.load' only fires once. Yes, it isn't desirable to use a non-public feature, but it works (for now) in cases where the desired behavior is a single firing. – Stonetip Aug 20 '22 at 14:56
1

Other answers suggest that map.on('styledata') is the correct approach. But it doesn't fire reliably, and the related isStyleLoaded is inaccurate.

Looks like we're stuck using style.load for now.

Mark d
  • 23
  • 4