簡體   English   中英

確保所有圖塊都加載到 Open Layers 3 XYZ 源中

[英]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;
}

我有兩個問題,任何人都可以就我們可能遺漏的內容提供任何其他想法嗎? 謝謝你的幫助。

  1. 當函數調用掛在tilegrid對象的原型上時,為什么它們在 ol-debug.js 而不是 ol.js 中可用
  2. 任何其他建議如何告訴所有圖塊已完全加載到地圖中?

加載事件

您假設源上的每個tileloadstart事件都應跟隨相應圖塊的tileloadendtileloaderror是正確的。 可以使用鏈接的官方示例來跟蹤加載圖塊的數量。

當發射的總和tileloadendtileloaderror事件等於數量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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM