繁体   English   中英

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

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

在OpenLayers 4.6.5中,我需要在循环中强制刷新地图视图,并等待刷新完成后再进行循环的下一次迭代。

在某些情况下:我正在对TileImage源的小多边形边界部分进行重复像素计算。 我已经能够一次让一个多边形使用我的计算功能,但是当我尝试将其放入循环以遍历所有多边形时,除非整个多边形在地图上可见,否则它将无法工作视图,并且多边形内的图块已加载。

因此,我现在尝试使循环工作,对于每个多边形:

  1. 重新放置地图视图,使其在缩放级别14处位于多边形的中心
  2. 刷新视图以确保所有图块均已加载
  3. 对多边形中的像素运行计算

我尝试使用异步函数和Promise,但无法使其正常工作-无论我如何尝试,我的forceRefresh函数都会运行200次(我有200个多边形),然后所有当前的图块都会加载视图,然后尝试对每个多边形(包括不在当前视图中的那些多边形)进行计算。

不幸的是,我不能仅缩放到所有多边形的范围并从该缩放级别运行所有计算。 由于不同缩放级别下像素大小的差异,因此在以缩放级别8与缩放级别14进行计算时,结果会有很大不同。

这些是我的代码的相关部分:

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');
        }
    });
}

注意,“ allTilesLoaded”属性由一个辅助函数设置,为简便起见,我省略了它,因为我认为这与这里的问题无关。

控制台中的输出如下:

(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

上面的最后一行显示了当尝试计算当前视图之外的多边形时发生的情况。

我希望看到以下内容:

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
...

编辑:请注意,我正在OL 4.6.5中工作,因此不幸的是,“ rendercomplete”不起作用。

使用“ rendercomplete”而不是“ postrender”。 这是一个新事件,“在渲染完成时触发,即所有源和图块均已完成当前视口的加载,并且所有图块都被淡入。”

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