【问题标题】:Mapbox GL JS: Style is not done loadingMapbox GL JS:样式未完成加载
【发布时间】:2017-11-07 17:45:30
【问题描述】:

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

我想知道样式已加载,然后添加一个图层。

根据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() 时收到此错误?

【问题讨论】:

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


【解决方案1】:

在向地图添加房地产标记时,我遇到了同样的问题。第一次添加标记,我等到地图空闲。添加一次后,我将其保存在 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();
        }

      }
    },

【讨论】:

    【解决方案2】:

    我最终得到: 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);
     });
    

    【讨论】:

      【解决方案3】:

      我创建了简单的解决方案。设置样式后给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();
      });
      

      【讨论】:

        【解决方案4】:

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

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

        我混合了两种解决方案。

        【讨论】:

        • 请注意 style.load 显然 not 是公共 API 的一部分,当样式是内联定义而不是从 URL 定义时,它似乎也不会触发: github.com/mapbox/mapbox-gl-js/issues/7579
        • 这在使用styledata 而不是style.load 时效果很好。谢谢!
        【解决方案5】:

        当前样式事件结构已损坏(至少从 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】:

        我的工作示例:

        当我改变风格时 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

        【讨论】:

          【解决方案7】:

          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() 有效但不能一直调用直到样式满载,你需要一个监听器而不是判断方法;

          【讨论】:

          • 我在mapbox-gl 1.1.1 中发现,如果不进行修改,这将无法正常工作:styledata 事件被多次触发,因此我在尝试重新添加已经存在的图层时遇到错误.我还需要创建一个布尔标志来跟踪是否已经添加了图层:当样式更改时它设置为false,当调用addLayer() 时设置为true。这很hackish,但似乎很有必要。
          • @thund 是正确的,此事件会被多次触发。此外,在样式完成加载之后,它实际上永远不会被触发。请参阅my answer 以获得更好的解决方案。
          【解决方案8】:

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

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

          【讨论】:

          【解决方案9】:

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

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

          // 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...
          
          }
          

          【讨论】:

          • 是的,我做了同样的事情,等待 Mapbox 团队修复该错误。
          • 我也在使用这个 hack,但从 MapBox v0.42.1 开始,检查isStyleLoaded 是不够的。我目前正在做typeof map.getSource('foo') === undefined。 (FWIW,我认为另一个答案是正确的,最好在地图和样式完成加载之前安排您的代码根本不运行。)
          • 第一个代码块完全没有必要。如果你曾经看到 return true 后跟 return false,只需返回条件。然后只剩下 mapbox isStyleLoaded() 调用的返回。你应该只有 var = map.isStyleLoaded()
          猜你喜欢
          • 2017-03-26
          • 1970-01-01
          • 1970-01-01
          • 2021-01-27
          • 2020-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多