Mapbox GL JS:样式未完成加载

问题描述 投票:0回答:10

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

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

根据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
10个回答
8
投票

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()
    可以工作,但不能一直调用,直到样式加载完毕,你需要一个监听器而不是一个判断方法;

7
投票

好吧,这个地图框问题很糟糕,但我有一个解决方案

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

我混合了两种解决方案。


3
投票

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

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

// 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
投票

使用

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

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

1
投票

我的工作示例:

当我改变风格时

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


1
投票

当前样式事件结构已被破坏(至少从 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;
  }
}

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();
        }

      }
    },


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

0
投票

您应该等待 Mapbox 地图样式完成加载,然后再向地图添加标记或图层。您可以通过侦听地图实例上的“style.load”事件来完成此操作。以下是如何执行此操作的示例:

// Inside the initializeMap function
map = new mappls.Map('map', {
  center: { lat, lng },
  zoom,
});

map.on('style.load', function () {
  // Map style has finished loading, you can now add markers or layers
  loadMyLayers();
});

这里我以我的印度地图为例


-1
投票

我创建了简单的解决方案。设置完样式后给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();
});
© www.soinside.com 2019 - 2024. All rights reserved.