[英]Ensuring all tiles are loaded in Open Layers 3 XYZ source
我們有一些層使用ol.source.XYZ
源。 對於加載策略,我們使用ol.loadingstrategy.tile(new ol.tilegrid.createXYZ({}))
。 在進行其他操作之前,我們需要確保所有圖塊都已完全加載到地圖視圖中。
我們遇到了多篇關於此的文章,但尚未找到 100% 的解決方案,這將為我們提供所需的解決方案。 即使情況並非如此,邏輯也會返回 true。 我們已經嘗試使用示例頁面上顯示的 tileloadstart、tileloadend、tileloaderror 事件,但這似乎並不總是返回預期的結果。
此處的 GIS Stack Exchange 文章似乎很有前景,因為我們可以將下面列出的代碼與 tileloadstart/tileloadend 事件結合使用,但有許多函數調用僅在ol-debug.js 中可用,而在ol.js源代碼中不可用. 因此,下面粘貼的代碼不適用於ol.js 。 此代碼只是引用的 GIS Stack Exchange 文章的副本。
function calculateNumberOfTiles(tileSource) {
var tg = (tileSource.getTileGrid()) ? tileSource.getTileGrid(): ol.tilegrid.getForProjection(map.getView().getProjection()),
z = tg.getZForResolution(map.getView().getResolution()),
tileRange = tg.getTileRangeForExtentAndZ(map.getView().calculateExtent(map.getSize()), z),
xTiles = tileRange['maxX'] - tileRange['minX'] + 1,
yTiles = tileRange['maxY'] - tileRange['minY'] + 1;
return xTiles * yTiles;
}
我有兩個問題,任何人都可以就我們可能遺漏的內容提供任何其他想法嗎? 謝謝你的幫助。
加載事件
您假設源上的每個tileloadstart
事件都應跟隨相應圖塊的tileloadend
或tileloaderror
是正確的。 可以使用鏈接的官方示例來跟蹤加載圖塊的數量。
當發射的總和tileloadend
和tileloaderror
事件等於數量tileloadstart
事件,沒有加載正在進行中。 如果不是這種情況,您應該嘗試制作一個可重現的示例,因為它可能是庫中的一個錯誤。
然而,了解這些事件的含義很重要。 tileloadend
事件並不表示該圖塊在地圖上可見,而是表示該圖塊已完成加載並可用於渲染。 tile 的實際渲染將在調用事件處理程序后完成。 因此,任何需要有關何時加載和渲染所有圖塊的信息的圖塊加載邏輯(例如在截取屏幕截圖/創建打印時)都必須等到下一個postrender
事件。
你提到了tileloadend
和實際出現在地圖上的 tile 之間的 5-10 秒,這對於渲染相關來說太長了(除非你做了一些非常奇怪的渲染回調)。
ol-debug.js 與 ol.js
與許多 JS 庫一樣,OpenLayers 代碼在構建過程中經過優化和最小化,以創建更小、更高效的構建。 任何不屬於 API 的類型或函數都將被縮小或刪除。 只應使用ol.js 中可用並記錄在openlayers.org上的方法,因為任何縮小的方法都可能會更改每個構建。
ol-debug.js 是該庫的非優化版本,用於調試或探索。
這是我的方法。 它使用未記錄的 API,但它適用於非調試 openlayers 4.2.0。
//"Dirty" tiles can be in one of two states: Either they are being downloaded,
//or the map is holding off downloading their replacement, and they are "wanted."
//We can tell when the map is ready when there are no tiles in either of these
//states, and rendering is done.
var numInFlightTiles = 0;
map.getLayers().forEach(function (layer) {
var source = layer.getSource();
if (source instanceof ol.source.TileImage) {
source.on('tileloadstart', function () {++numInFlightTiles})
source.on('tileloadend', function () {--numInFlightTiles})
}
})
map.on('postrender', function (evt) {
if (!evt.frameState)
return;
var numHeldTiles = 0;
var wanted = evt.frameState.wantedTiles;
for (var layer in wanted)
if (wanted.hasOwnProperty(layer))
numHeldTiles += Object.keys(wanted[layer]).length;
var ready = numInFlightTiles === 0 && numHeldTiles === 0;
if (map.get('ready') !== ready)
map.set('ready', ready);
});
map.set('ready', false);
function whenMapIsReady(callback) {
if (map.get('ready'))
callback();
else
map.once('change:ready', whenMapIsReady.bind(null, callback));
}
此答案已過時,並且不適用於 openlayers 6 或更高版本。
如此處所述: https : //github.com/openlayers/openlayers/releases/tag/v6.0.0
對此的解決方案是將后渲染放在這樣的圖層上
const mapLayer = map.getLayers().getArray()[0];
mapLayer.on('postrender', (evt) => {});
這將在渲染第一層后觸發后渲染
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.