Mapbox GL JS:样式未完成加载

Posted

技术标签:

【中文标题】Mapbox GL JS:样式未完成加载【英文标题】:Mapbox GL JS: Style is not done loading 【发布时间】: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() 时收到此错误?

【问题讨论】:

Style is not done loading: Mapbox GL JS的可能重复 【参考方案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;
  

【讨论】:

对于某些样式,它可以工作,isStyleLoaded 在最终的styledata 事件上返回 true,而对于某些样式则不起作用 (1.12.0)。 相关问题:github.com/mapbox/mapbox-gl-js/issues/8691【参考方案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。不应使用上述其他方法的原因

    setTimeout 可能有效,但不是解决问题的推荐方法,如果您的渲染工作繁重,您会得到意想不到的结果; style.load 是 mapbox 中的一个私人事件,正如问题 https://github.com/mapbox/mapbox-gl-js/issues/7579 中所讨论的,所以我们显然不应该听它; .isStyleLoaded() 有效但不能一直调用直到样式满载,你需要一个监听器而不是判断方法;

【讨论】:

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

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

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

【讨论】:

请注意 style.load 显然 not 是公共 API 的一部分,当样式是内联定义而不是从 URL 定义时,它似乎也不会触发: github.com/mapbox/mapbox-gl-js/issues/7579【参考方案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()

以上是关于Mapbox GL JS:样式未完成加载的主要内容,如果未能解决你的问题,请参考以下文章

Leaflet.js 中未显示自定义 Mapbox 瓦片集

MapBox GL Android:来自自定义图块源的离线地图已下载但未使用

Mapbox GL js 可用图标

我可以使用传单插件和mapbox gl js吗?

在 Mapbox-GL-JS 中 minzoom 和 maxzoom 到底做了啥?

通过 mapbox gl js 向 mapbox 中的地图添加一些基本标记