Mapbox GL JS:样式未加载

时间:2017-06-06 15:49:12

标签: mapbox mapbox-gl-js mapbox-gl

我有一张地图,我们可以经典地从一种风格切换到另一种风格,例如街道到卫星。

我希望被告知已加载样式然后添加图层。

根据doc,我试图等待加载的样式添加基于GEOJson数据集的图层。

当加载页面时触发map.on('load')时效果很好但是当我改变样式时出现错误,所以当从map.on('styledataloading')添加图层时,我甚至在Firefox中遇到内存问题。

我的代码是:

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"]
    });
  });
}

错误是:

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)

为什么我会在测试样式加载后调用loadRegionMask()时出现此错误?

9 个答案:

答案 0 :(得分:2)

我遇到了类似的问题并最终得到了这个解决方案:

我创建了一个小函数来检查样式是否已完成加载:

// Check if the Mapbox-GL style is loaded.
function checkIfMapboxStyleIsLoaded() {
  if (map.isStyleLoaded()) {
    return true; // When it is safe to manipulate layers
  } else {
    return false; // When it is not safe to manipulate layers
  }
}

然后每当我交换或修改应用程序中的图层时,我都会使用如下函数:

function swapLayer() {
  var check = checkIfMapboxStyleIsLoaded();
  if (!check) {
    // It's not safe to manipulate layers yet, so wait 200ms and then check again
    setTimeout(function() {
      swapLayer();
    }, 200);
    return;
  }

  // Whew, now it's safe to manipulate layers!
  the rest of the swapLayer logic goes here...

}

答案 1 :(得分:2)

1。收听styledata事件来解决您的问题

您可能需要在项目中监听styledata事件,因为这是mapbox-gl-js文档中提到的唯一标准事件,请参见https://docs.mapbox.com/mapbox-gl-js/api/#map.event:styledata

您可以通过以下方式使用它:

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

2。为什么不应该使用上述其他方法的原因

  1. setTimeout可能有效,但不是解决此问题的推荐方法,如果渲染工作繁重,您将得到意想不到的结果;
  2. style.load是mapbox中的私有事件,如问题https://github.com/mapbox/mapbox-gl-js/issues/7579所述,因此我们不应该明显地听它;
  3. .isStyleLoaded()有效,但是直到样式完全加载后才能一直被调用,您需要一个侦听器而不是一种判断方法;

答案 2 :(得分:1)

使用style.load事件。每次加载新样式时都会触发一次。

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

答案 3 :(得分:1)

好的,这个mapbox问题很糟糕,但是我有解决方案

myMap.on('style.load', () => {
  const waiting = () => {
    if (!myMap.isStyleLoaded()) {
      setTimeout(waiting, 200);
    } else {
      loadMyLayers();
    }
  };
  waiting();
});

我将两种解决方案混合在一起。

答案 4 :(得分:0)

我的工作示例:

当我改变风格时 map.setStyle()

我收到错误Uncaught Error: Style is not done loading

这解决了我的问题

请勿使用map.on("load", loadTiles);

代替

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

更改样式map.setStyle()时,必须等待setStyle()完成,然后再添加其他图层。          到目前为止map.setStyle('xxx', callback)不允许。要等到回调,解决方法是使用map.on("styledata"          如果您更改map.on("load",则map.setStyle()不起作用。您会收到错误消息:Uncaught Error: Style is not done loading

答案 5 :(得分:0)

当前样式事件结构已损坏(至少从Mapbox GL v1.3.0开始)。如果您在styledata事件处理程序中检查map.isStyleLoaded(),它将始终解析为false:

map.on('styledata', function (e) {
  if (map.isStyleLoaded()){
    // This never happens...
  }
}

我的解决方案是创建一个名为“ style_finally_loaded”的新事件,该事件仅在样式实际加载后才触发一次:

var checking_style_status = false;
map.on('styledata', function (e) {
  if (checking_style_status){
    // If already checking style status, bail out
    // (important because styledata event may fire multiple times)
    return;
  } else {
    checking_style_status = true;
    check_style_status();
  }
});
function check_style_status() {
  if (map.isStyleLoaded()) {
    checking_style_status = false;
    map._container.trigger('map_style_finally_loaded');
  } else {
    // If not yet loaded, repeat check after delay:
    setTimeout(function() {check_style_status();}, 200);
    return;
  }
}

答案 6 :(得分:0)

我创建了简单的解决方案。设置好样式后给mapbox 1秒加载样式就可以绘制图层了

map.setStyle(styleUrl);     
setTimeout(function(){
   reDrawMapSourceAndLayer(); /// your function layer
}, 1000);

当您使用 map.on('styledataloading') 时,它会在您更改样式时触发几次

map.on('styledataloading', () => {
  const waiting = () => {
    if (!myMap.isStyleLoaded()) {
      setTimeout(waiting, 200);
    } else {
      loadMyLayers();
    }
  };
  waiting();
});

答案 7 :(得分:0)

我最终得到: map.once("idle", ()=>{ ... some function here}); 如果你有一堆你想做的事情,我会做这样的事情 => 将它们添加到一个看起来像 [{func: function, param: params}] 的数组中,然后你有另一个执行此操作的函数:

executeActions(actions) {
  actions.forEach((action) => {
  action.func(action.params);
});

最后你有

this.map.once("idle", () => {
    this.executeActions(actionsArray);
 });

答案 8 :(得分:0)

我在向地图添加房地产标记时遇到了同样的问题。第一次添加标记时,我会等到地图闲置。添加后,我将其保存在 realEstateWasInitialLoaded 中,然后无需等待就添加它。但请确保在更改基本地图或类似内容时将 realEstateWasInitialLoaded 重置为 false。

checkIfRealEstateLayerCanBeAddedAndAdd() {
      /* The map must exist and real estates must be ready */
      if (this.map && this.realEstates) {
        this.map.once('idle', () => {
          if (!this.realEstateWasInitialLoaded) {
            this.addRealEstatesLayer();
            this.realEstateWasInitialLoaded = true
          }
        })
        if(this.realEstateWasInitialLoaded) {
          this.addRealEstatesLayer();
        }

      }
    },