我有一张地图,我们可以在其中经典地从一种风格切换到另一种风格,例如从街道切换到卫星。
我想知道样式已加载然后添加图层。
根据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()
时会出现此错误?
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()
可以工作,但不能一直调用,直到样式加载完毕,你需要一个监听器而不是一个判断方法;好吧,这个地图框问题很糟糕,但我有一个解决方案
myMap.on('styledata', () => {
const waiting = () => {
if (!myMap.isStyleLoaded()) {
setTimeout(waiting, 200);
} else {
loadMyLayers();
}
};
waiting();
});
我混合了两种解决方案。
我面临着类似的问题,最终得到了这个解决方案:
我创建了一个小函数来检查样式是否已完成加载:
// 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...
}
使用
style.load
事件。每次加载新样式时都会触发一次。
map.on('style.load', function() {
addLayer();
});
我的工作示例:
当我改变风格时
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
当前样式事件结构已被破坏(至少从 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;
}
}
在向地图添加房地产标记时,我遇到了同样的问题。第一次添加标记时,我会等到地图空闲。添加后,我将其保存在 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();
}
}
},
我最终得到:
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);
});
您应该等待 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();
});
这里我以我的印度地图为例
我创建了简单的解决方案。设置完样式后给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();
});