Ensuring all tiles are loaded in Open Layers 3 XYZ source

僤鯓⒐⒋嵵緔 提交于 2019-12-01 15:58:46

Loading events

You are correct in assuming that each tileloadstart event on the source should be followed by a tileloadend or tileloaderror for the corresponding tile. That can be used, as in the linked official example, to keep track of the number of loading tiles.

When the sum of emitted tileloadend and tileloaderror events equal the number of tileloadstart events, no loading is in progress. If this is not the case, you should try to make a reproducible example, as it would probably be a bug in the library.

It is however important to understand what these events mean. The tileloadend event does not mean that the tile is visible on the map, it means that the tile has finished loading and is usable for rendering. The actual rendering of the tile will be done after the event handler is invoked. So any tile loading logic requiring information about when all tiles are loaded and rendered (such when taking screenshots/creating prints) will have to wait until the next postrender event.

You mention 5-10 seconds between a tileloadend and the tile actually appearing on the map, which is too long for it to be rendering related (unless you do some really freaky rendering callbacks).

ol-debug.js vs ol.js

Like many JS libraries, OpenLayers code is optimized and minimized in the build process to create smaller and more efficient builds. Any type or function that is not part of the API will be minified or removed. Only the methods available in ol.js, and documented on openlayers.org, should be used as any minified methods may change each build.

ol-debug.js is a non-optimized version of the library, intended for use when debugging or exploring.

This is my approach. It uses an undocumented API, but it works in non-debug 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));
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!