В OpenLayers 4.6.5 мне нужно принудительно обновить представление карты в цикле и ждать завершения обновления, прежде чем перейти к следующей итерации цикла.
Для некоторого контекста: Я делаю повторяющиеся расчеты пикселей на маленьких ограниченных многоугольниками участках источника TileImage.Мне удалось заставить мою функцию расчета работать с одним полигоном за раз, но когда я пытаюсь поместить ее в цикл для прохождения всех полигонов, она не будет работать, если весь полигон не виден на картеи плитки внутри полигона загружены.
Итак, я сейчас пытаюсь заставить работать цикл, который для каждого полигона:
- Перемещает вид карты так, чтобы онцентрируется на многоугольнике с уровнем увеличения 14
- Обновляет представление, чтобы убедиться, что все плитки загружены
- Запускает вычисление для пикселей в многоугольнике
I 'мы пытались поиграться с асинхронными функциями и обещаниями, но не могли заставить его работать должным образом - независимо от того, что я пытаюсь, моя функция 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', к сожалению, не работает.