From 7c3c1ac35489167272888a90ec32c3cc4a7c1035 Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 1 Feb 2022 14:23:57 +0100 Subject: [PATCH] Fix rendercomplete for WebGLPoints layer and subclasses --- src/ol/PluggableMap.js | 7 ++- src/ol/renderer/Layer.js | 5 ++ src/ol/renderer/webgl/PointsLayer.js | 5 +- test/browser/spec/ol/Map.test.js | 16 ++++- .../ol/renderer/webgl/PointsLayer.test.js | 60 +++++++++++++++++++ 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/ol/PluggableMap.js b/src/ol/PluggableMap.js index 0748e53a0b..7789659751 100644 --- a/src/ol/PluggableMap.js +++ b/src/ol/PluggableMap.js @@ -943,10 +943,13 @@ class PluggableMap extends BaseObject { /** * @return {boolean} Layers have sources that are still loading. */ - getLoading() { + getLoadingOrNotReady() { const layerStatesArray = this.getLayerGroup().getLayerStatesArray(); for (let i = 0, ii = layerStatesArray.length; i < ii; ++i) { const layer = layerStatesArray[i].layer; + if (!layer.getRenderer().ready) { + return true; + } const source = /** @type {import("./layer/Layer.js").default} */ ( layer ).getSource(); @@ -1561,7 +1564,7 @@ class PluggableMap extends BaseObject { this.renderComplete_ = !this.tileQueue_.getTilesLoading() && !this.tileQueue_.getCount() && - !this.getLoading(); + !this.getLoadingOrNotReady(); if (!this.postRenderTimeoutHandle_) { this.postRenderTimeoutHandle_ = setTimeout(() => { diff --git a/src/ol/renderer/Layer.js b/src/ol/renderer/Layer.js index aff95f60bf..eb65ebd6e3 100644 --- a/src/ol/renderer/Layer.js +++ b/src/ol/renderer/Layer.js @@ -17,6 +17,11 @@ class LayerRenderer extends Observable { constructor(layer) { super(); + /** + * @type {boolean} The renderer is initialized and ready to render. + */ + this.ready = true; + /** @private */ this.boundHandleImageChange_ = this.handleImageChange_.bind(this); diff --git a/src/ol/renderer/webgl/PointsLayer.js b/src/ol/renderer/webgl/PointsLayer.js index d66b2b4601..f0b9afe7d3 100644 --- a/src/ol/renderer/webgl/PointsLayer.js +++ b/src/ol/renderer/webgl/PointsLayer.js @@ -137,6 +137,8 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer { postProcesses: options.postProcesses, }); + this.ready = false; + this.sourceRevision_ = -1; this.verticesBuffer_ = new WebGLArrayBuffer(ARRAY_BUFFER, DYNAMIC_DRAW); @@ -320,7 +322,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer { event.data.renderInstructions ); } - + this.ready = true; this.getLayer().changed(); } }.bind(this) @@ -610,6 +612,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer { }; // additional properties will be sent back as-is by the worker message['projectionTransform'] = projectionTransform; + this.ready = false; this.worker_.postMessage(message, [this.renderInstructions_.buffer]); this.renderInstructions_ = null; diff --git a/test/browser/spec/ol/Map.test.js b/test/browser/spec/ol/Map.test.js index 505d12570d..1f7d5518d0 100644 --- a/test/browser/spec/ol/Map.test.js +++ b/test/browser/spec/ol/Map.test.js @@ -23,6 +23,7 @@ import TileLayerRenderer from '../../../../src/ol/renderer/canvas/TileLayer.js'; import VectorLayer from '../../../../src/ol/layer/Vector.js'; import VectorSource from '../../../../src/ol/source/Vector.js'; import View from '../../../../src/ol/View.js'; +import WebGLPointsLayer from '../../../../src/ol/layer/WebGLPoints.js'; import XYZ from '../../../../src/ol/source/XYZ.js'; import {LineString, Point, Polygon} from '../../../../src/ol/geom.js'; import {TRUE} from '../../../../src/ol/functions.js'; @@ -449,6 +450,17 @@ describe('ol/Map', function () { }, }), }), + new WebGLPointsLayer({ + source: new VectorSource({ + features: [new Feature(new Point([0, 0]))], + }), + style: { + symbol: { + color: 'red', + symbolType: 'circle', + }, + }, + }), ], }); }); @@ -460,13 +472,15 @@ describe('ol/Map', function () { }); it('triggers when all tiles and sources are loaded and faded in', function (done) { + const layers = map.getLayers().getArray(); + expect(layers[6].getRenderer().ready).to.be(false); map.once('rendercomplete', function () { - const layers = map.getLayers().getArray(); expect(map.tileQueue_.getTilesLoading()).to.be(0); expect(layers[1].getSource().image_.getState()).to.be( ImageState.LOADED ); expect(layers[2].getSource().getFeatures().length).to.be(1); + expect(layers[6].getRenderer().ready).to.be(true); done(); }); map.setView( diff --git a/test/browser/spec/ol/renderer/webgl/PointsLayer.test.js b/test/browser/spec/ol/renderer/webgl/PointsLayer.test.js index eddf3799da..e4901289eb 100644 --- a/test/browser/spec/ol/renderer/webgl/PointsLayer.test.js +++ b/test/browser/spec/ol/renderer/webgl/PointsLayer.test.js @@ -1,8 +1,10 @@ import Feature from '../../../../../../src/ol/Feature.js'; import GeoJSON from '../../../../../../src/ol/format/GeoJSON.js'; +import Map from '../../../../../../src/ol/Map.js'; import Point from '../../../../../../src/ol/geom/Point.js'; import VectorLayer from '../../../../../../src/ol/layer/Vector.js'; import VectorSource from '../../../../../../src/ol/source/Vector.js'; +import View from '../../../../../../src/ol/View.js'; import ViewHint from '../../../../../../src/ol/ViewHint.js'; import WebGLPointsLayer from '../../../../../../src/ol/layer/WebGLPoints.js'; import WebGLPointsLayerRenderer from '../../../../../../src/ol/renderer/webgl/PointsLayer.js'; @@ -11,6 +13,7 @@ import { compose as composeTransform, create as createTransform, } from '../../../../../../src/ol/transform.js'; +import {createCanvasContext2D} from '../../../../../../src/ol/dom.js'; import {get as getProjection} from '../../../../../../src/ol/proj.js'; import {getUid} from '../../../../../../src/ol/util.js'; @@ -688,4 +691,61 @@ describe('ol/renderer/webgl/PointsLayer', function () { renderer.renderFrame(frameState); }); }); + + describe('rendercomplete', function () { + let map, layer; + beforeEach(function () { + layer = new WebGLPointsLayer({ + source: new VectorSource({ + features: [new Feature(new Point([0, 0]))], + }), + style: { + symbol: { + symbolType: 'circle', + size: 14, + color: 'red', + }, + }, + }); + map = new Map({ + pixelRatio: 1, + target: createMapDiv(100, 100), + layers: [layer], + view: new View({ + center: [0, 0], + zoom: 2, + }), + }); + }); + + afterEach(function () { + disposeMap(map); + }); + + it('is completely rendered on rendercomplete', function (done) { + map.once('rendercomplete', function () { + const targetContext = createCanvasContext2D(1, 1); + const canvas = document.querySelector('.ol-layer'); + targetContext.drawImage(canvas, 50, 50, 1, 1, 0, 0, 1, 1); + expect(Array.from(targetContext.getImageData(0, 0, 1, 1).data)).to.eql([ + 255, 0, 0, 255, + ]); + layer + .getSource() + .addFeature(new Feature(new Point([1900000, 1900000]))); + layer.once('postrender', function () { + expect(layer.getRenderer().ready).to.be(false); + }); + map.once('rendercomplete', function () { + const targetContext = createCanvasContext2D(1, 1); + const canvas = document.querySelector('.ol-layer'); + targetContext.drawImage(canvas, 99, 0, 1, 1, 0, 0, 1, 1); + expect( + Array.from(targetContext.getImageData(0, 0, 1, 1).data) + ).to.eql([255, 0, 0, 255]); + done(); + }); + }); + }); + }); });