我有一张地图,我们可以经典地从一种风格切换到另一种风格,例如街道到卫星。
我希望被告知已加载样式然后添加图层。
根据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()
时出现此错误?
答案 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)
styledata
事件来解决您的问题您可能需要在项目中监听styledata
事件,因为这是mapbox-gl-js文档中提到的唯一标准事件,请参见https://docs.mapbox.com/mapbox-gl-js/api/#map.event:styledata。
您可以通过以下方式使用它:
map.on('styledata', function() {
addLayer();
});
setTimeout
可能有效,但不是解决此问题的推荐方法,如果渲染工作繁重,您将得到意想不到的结果; style.load
是mapbox中的私有事件,如问题https://github.com/mapbox/mapbox-gl-js/issues/7579所述,因此我们不应该明显地听它; .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();
}
}
},