简体   繁体   English

OpenLayers:如何在循环中强制刷新视图和图块

[英]OpenLayers: How to force a refresh of view and tiles within a loop

In OpenLayers 4.6.5, I need to force a refresh of the map view within a loop, and wait for the refresh to be completed before proceeding to the next iteration of the loop. 在OpenLayers 4.6.5中,我需要在循环中强制刷新地图视图,并等待刷新完成后再进行循环的下一次迭代。

For some context: I'm doing repetitive pixel calculations on small polygon-bounded sections of a TileImage source. 在某些情况下:我正在对TileImage源的小多边形边界部分进行重复像素计算。 I've been able to get my calculation function working with one polygon at a time, but when I try to put it into a loop to run through all of the polygons, it won't work unless the whole polygon is visible in the map view, and the tiles within the polygon have loaded. 我已经能够一次让一个多边形使用我的计算功能,但是当我尝试将其放入循环以遍历所有多边形时,除非整个多边形在地图上可见,否则它将无法工作视图,并且多边形内的图块已加载。

So I'm now trying to get a loop to work which, for each polygon: 因此,我现在尝试使循环工作,对于每个多边形:

  1. Repositions the map view so it is centered on the polygon at zoom level 14 重新放置地图视图,使其在缩放级别14处位于多边形的中心
  2. Refreshes the view to ensure all tiles have loaded 刷新视图以确保所有图块均已加载
  3. Runs the calculation for the pixels in the polygon 对多边形中的像素运行计算

I've tried playing around with async functions and promises, but can't get it to work properly - no matter what I try, my forceRefresh function runs 200 times (I have 200 polygons), and then all my tiles load for the current view, and then the calculation is attempted for each polygon, including those not in the current view. 我尝试使用异步函数和Promise,但无法使其正常工作-无论我如何尝试,我的forceRefresh函数都会运行200次(我有200个多边形),然后所有当前的图块都会加载视图,然后尝试对每个多边形(包括不在当前视图中的那些多边形)进行计算。

Unfortunately I can't just zoom to the extent of all of the polygons and run all of the calculations from that zoom level. 不幸的是,我不能仅缩放到所有多边形的范围并从该缩放级别运行所有计算。 Due to differences in pixel sizes at different zoom levels, the results vary considerably when the calculation is run at say zoom level 8 vs zoom level 14. 由于不同缩放级别下像素大小的差异,因此在以缩放级别8与缩放级别14进行计算时,结果会有很大不同。

These are the relevant parts of my code: 这些是我的代码的相关部分:

function forceRefresh(source,ms) {
    return new Promise(resolve => {
        source.refresh();
        map.updateSize();
        setTimeout(() => {
            resolve('Map should now be refreshed');
        }, ms);
    });
}

async function getCellAverage(featureID,equation,calcZoom=14) {
    return new Promise(resolve => {
        initialZoom = view.getZoom();
        initialCenter = view.getCenter();
        layerSource = window["layer" + featureID].getSource();
        window["allTilesLoaded"] = false;
        zoomToFit("source"+featureID);
        if(view.getZoom() > calcZoom) {
            view.setZoom(calcZoom);
        }
        layerSource.getFeatures().forEach(async function(feature) {
            var result = await forceRefresh(window['L8SourceNRG'],100);
            console.log(result);
            var geom = feature.getGeometry();
            var size = map.getSize();
            var ndviArray = [];
            map.addEventListener('postrender', function() {
                if(window['L8SourceNRG'].allTilesLoaded == true) {
                    console.log('Confirmed all L8SourceNRG tiles loaded');
                    map.removeEventListener('postrender');
                    if (geom.intersectsExtent(map.getView().calculateExtent(size))) {
                        for (var i=0; i<size[0]; i++) {
                            for (var j=0; j<size[1]; j++) {
                                var coordinate = map.getCoordinateFromPixel([i,j]);
                                if (geom.intersectsCoordinate(coordinate)) {
                                    let tileCoord = L8SourceTileGrid.getTileCoordForCoordAndResolution(coordinate, map.getView().getResolution());
                                    let key = tileCoord.join('-');
                                    if (key in window['tiles']) {
                                        let origin = L8SourceTileGrid.getOrigin(tileCoord[0]);
                                        let res = L8SourceTileGrid.getResolution(tileCoord[0]);
                                        let tileSize = L8SourceTileGrid.getTileSize(tileCoord[0]);
                                        var w = Math.floor(((coordinate[0] - origin[0]) / res) % (tileSize[0] | tileSize));
                                        var h = Math.floor(((origin[1] - coordinate[1]) / res) % (tileSize[1] | tileSize));

                                        var canvas = document.createElement("canvas");
                                        canvas.width = tiles[key].width;
                                        canvas.height = tiles[key].height;

                                        var ctx = canvas.getContext("2d");
                                        ctx.drawImage(tiles[key], 0, 0);

                                        let img = ctx.getImageData(0, 0, canvas.width, canvas.height);
                                        let imgData = img.data;

                                        let index = (w + h * 256) * 4;
                                        let pixel = [imgData[index + 0], imgData[index + 1], imgData[index + 2], imgData[index + 3]];
                                        ndviArray.push((( pixel[0] - pixel[1] ) / ( pixel[0] + pixel[1] )));

                                    }
                                }
                            }
                        }
                    }

                    var ndviSum = ndviArray.reduce((a, b) => a + b, 0);
                    var ndviAvg = ndviSum / ndviArray.length;

                    console.log("Average NDVI: "+ndviAvg);

                    makePolygonMask("avgNDVI",featureID,geom,ndviAvg);
                    window['cellAverageDone'] = true;
                }
            });
        });

        setTimeout(() => {
            resolve('resolved');
        }, 100);
    });
}

async function getAllAverages(equation) {
    map.getLayers().forEach(async function(layer) {
        window['cellAverageDone'] = false;
        if (layer.get('type') == "cell") {
            layerID = layer.get('name').substring(9);
            var result = await getCellAverage(layer.get('name').substring(5),'NDVI');
        }
    });
}

NB the "allTilesLoaded" property is set by a helper function, which for brevity I've left out as I don't think it's relevant to the question here. 注意,“ allTilesLoaded”属性由一个辅助函数设置,为简便起见,我省略了它,因为我认为这与这里的问题无关。

The output in the console is as follows: 控制台中的输出如下:

(200x) Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.37295137830077313
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.38384215219470413
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.44356048105512613
...
Confirmed all L8SourceNRG tiles loaded
Average NDVI: NaN

The last line above shows what happens when the calculation is attempted for a polygon which is outside the current view. 上面的最后一行显示了当尝试计算当前视图之外的多边形时发生的情况。

I am expecting to see the following instead: 我希望看到以下内容:

Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.37295137830077313
Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.38384215219470413
Map should now be refreshed
Confirmed all L8SourceNRG tiles loaded
Average NDVI: 0.44356048105512613
...

EDIT: Note that I'm working in OL 4.6.5, so 'rendercomplete' unfortunately doesn't work. 编辑:请注意,我正在OL 4.6.5中工作,因此不幸的是,“ rendercomplete”不起作用。

Use 'rendercomplete' instead of 'postrender'. 使用“ rendercomplete”而不是“ postrender”。 This is a new event that is "triggered when rendering is complete, ie all sources and tiles have finished loading for the current viewport, and all tiles are faded in." 这是一个新事件,“在渲染完成时触发,即所有源和图块均已完成当前视口的加载,并且所有图块都被淡入。”

https://openlayers.org/en/latest/apidoc/module-ol_render_Event-RenderEvent.html#event:rendercomplete https://openlayers.org/en/latest/apidoc/module-ol_render_Event-RenderEvent.html#event:rendercomplete

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

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