简体   繁体   English

确保所有图块都加载到 Open Layers 3 XYZ 源中

[英]Ensuring all tiles are loaded in Open Layers 3 XYZ source

We have some layers that make use of a ol.source.XYZ source.我们有一些层使用ol.source.XYZ源。 For the loading strategy we use ol.loadingstrategy.tile(new ol.tilegrid.createXYZ({})) .对于加载策略,我们使用ol.loadingstrategy.tile(new ol.tilegrid.createXYZ({})) We need to ensure that all tiles have been completely loaded in the map view before proceeding with other operations.在进行其他操作之前,我们需要确保所有图块都已完全加载到地图视图中。

We have come across multiple articles regarding this and haven't found a 100% solution yet that will give us the solution we need.我们遇到了多篇关于此的文章,但尚未找到 100% 的解决方案,这将为我们提供所需的解决方案。 The logic returns true even when it's not the case.即使情况并非如此,逻辑也会返回 true。 We've tried to make use of the tileloadstart, tileloadend, tileloaderror events as shown on theexample page but this doesn't seem to always return the expected result.我们已经尝试使用示例页面上显示的 tileloadstart、tileloadend、tileloaderror 事件,但这似乎并不总是返回预期的结果。

The GIS Stack Exchange article here seemed promising because we could use the code listed below in conjunction with tileloadstart/tileloadend events but there are a number of the function calls that are only available in ol-debug.js and not the ol.js source code. 此处的 GIS Stack Exchange 文章似乎很有前景,因为我们可以将下面列出的代码与 tileloadstart/tileloadend 事件结合使用,但有许多函数调用仅在ol-debug.js 中可用,而在ol.js源代码中不可用. Because of this the code pasted below does not work with ol.js .因此,下面粘贴的代码不适用于ol.js This code is just a copy from the referenced GIS Stack Exchange article.此代码只是引用的 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;
}

I have two questions, can anyone please provide any additional thoughts in what we may be missing?我有两个问题,任何人都可以就我们可能遗漏的内容提供任何其他想法吗? Thanks for your help.谢谢你的帮助。

  1. Why are the function calls available in ol-debug.js and not ol.js when they hang off of the prototype of tilegrid object?当函数调用挂在tilegrid对象的原型上时,为什么它们在 ol-debug.js 而不是 ol.js 中可用
  2. Any other suggestions how to tell all tiles are completely loaded in the map?任何其他建议如何告诉所有图块已完全加载到地图中?

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.您假设源上的每个tileloadstart事件都应跟随相应图块的tileloadendtileloaderror是正确的。 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.当发射的总和tileloadendtileloaderror事件等于数量tileloadstart事件,没有加载正在进行中。 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. tileloadend事件并不表示该图块在地图上可见,而是表示该图块已完成加载并可用于渲染。 The actual rendering of the tile will be done after the event handler is invoked. tile 的实际渲染将在调用事件处理程序后完成。 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.因此,任何需要有关何时加载和渲染所有图块的信息的图块加载逻辑(例如在截取屏幕截图/创建打印时)都必须等到下一个postrender事件。

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).你提到了tileloadend和实际出现在地图上的 tile 之间的 5-10 秒,这对于渲染相关来说太长了(除非你做了一些非常奇怪的渲染回调)。

ol-debug.js vs ol.js ol-debug.js 与 ol.js

Like many JS libraries, OpenLayers code is optimized and minimized in the build process to create smaller and more efficient builds.与许多 JS 库一样,OpenLayers 代码在构建过程中经过优化和最小化,以创建更小、更高效的构建。 Any type or function that is not part of the API will be minified or removed.任何不属于 API 的类型或函数都将被缩小或删除。 Only the methods available in ol.js, and documented on openlayers.org , should be used as any minified methods may change each build.只应使用ol.js 中可用并记录在openlayers.org上的方法,因为任何缩小的方法都可能会更改每个构建。

ol-debug.js is a non-optimized version of the library, intended for use when debugging or exploring. ol-debug.js 是该库的非优化版本,用于调试或探索。

This is my approach.这是我的方法。 It uses an undocumented API, but it works in non-debug openlayers 4.2.0.它使用未记录的 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));
}

This answer is outdated and does not work from openlayers 6 or higher.此答案已过时,并且不适用于 openlayers 6 或更高版本。

As documented here: https://github.com/openlayers/openlayers/releases/tag/v6.0.0如此处所述: https : //github.com/openlayers/openlayers/releases/tag/v6.0.0

A solution to this is to put the postrender on a layer like this对此的解决方案是将后渲染放在这样的图层上

const mapLayer = map.getLayers().getArray()[0];

mapLayer.on('postrender', (evt) => {});

This triggers the postrender after the first layer is rendered这将在渲染第一层后触发后渲染

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM