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:样式未完成加载的主要内容,如果未能解决你的问题,请参考以下文章
MapBox GL Android:来自自定义图块源的离线地图已下载但未使用