Mapbox GL JS: Style is not done loading

fralbo picture fralbo · Jun 6, 2017 · Viewed 7.2k times · Source

I have a map wher we can classically switch from one style to another, streets to satellite for example.

I want to be informed that the style is loaded to then add a layer.

According to the doc, I tried to wait that the style being loaded to add a layer based on a GEOJson dataset.

That works perfectly when the page is loaded which fires map.on('load') but I get an error when I just change the style, so when adding layer from map.on('styledataloading'), and I even get memory problems in Firefox.

My code is:

mapboxgl.accessToken = 'pk.token';
var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v10',
    center: [5,45.5],
    zoom: 7
});

map.on('load', function () {

    loadRegionMask();
});

map.on('styledataloading', function (styledata) {

    if (map.isStyleLoaded()) {
        loadRegionMask();
    }
});

$('#typeMap').on('click', function switchLayer(layer) {
    var layerId = layer.target.control.id;

    switch (layerId) {
        case 'streets':
            map.setStyle('mapbox://styles/mapbox/' + layerId + '-v10');
        break;

        case 'satellite':
            map.setStyle('mapbox://styles/mapbox/satellite-streets-v9');
        break;
    }
});

function loadJSON(callback) {   

  var xobj = new XMLHttpRequest();
      xobj.overrideMimeType("application/json");

  xobj.open('GET', 'regions.json', true);

  xobj.onreadystatechange = function () {
        if (xobj.readyState == 4 && xobj.status == "200") {
          callback(xobj.responseText);
        }
  };
  xobj.send(null);  
}

function loadRegionMask() {

  loadJSON(function(response) {

    var geoPoints_JSON = JSON.parse(response);

    map.addSource("region-boundaries", {
      'type': 'geojson',
      'data': geoPoints_JSON,
    });

    map.addLayer({
        'id': 'region-fill',
        'type': 'fill',
        'source': "region-boundaries",
        'layout': {},
        'paint': {
            'fill-color': '#C4633F',
            'fill-opacity': 0.5
        },
        "filter": ["==", "$type", "Polygon"]
    });
  });
}

And the error is:

Uncaught Error: Style is not done loading
    at t._checkLoaded (mapbox-gl.js:308)
    at t.addSource (mapbox-gl.js:308)
    at e.addSource (mapbox-gl.js:390)
    at map.js:92 (map.addSource("region-boundaries",...)
    at XMLHttpRequest.xobj.onreadystatechange (map.js:63)

Why do I get this error whereas I call loadRegionMask() after testing that the style is loaded?

Answer

hijiangtao picture hijiangtao · Jan 26, 2019

1. Listen styledata event to solve your problem

You may need to listen styledata event in your project, since this is the only standard event mentioned in mapbox-gl-js documents, see https://docs.mapbox.com/mapbox-gl-js/api/#map.event:styledata.

You can use it in this way:

map.on('styledata', function() {
    addLayer();
});

2. Reasons why you shouldn't use other methods mentioned above

  1. setTimeout may work but is not a recommend way to solve the problem, and you would got unexpected result if your render work is heavy;
  2. style.load is a private event in mapbox, as discussed in issue https://github.com/mapbox/mapbox-gl-js/issues/7579, so we shouldn't listen to it apparently;
  3. .isStyleLoaded() works but can't be called all the time until style is full loaded, you need a listener rather than a judgement method;