diff --git a/src/ol/Disposable.js b/src/ol/Disposable.js index da4cb6b60f..d7800fa2b8 100644 --- a/src/ol/Disposable.js +++ b/src/ol/Disposable.js @@ -14,15 +14,15 @@ class Disposable { * @type {boolean} * @private */ - this.disposed = false; + this.disposed_ = false; } /** * Clean up. */ dispose() { - if (!this.disposed) { - this.disposed = true; + if (!this.disposed_) { + this.disposed_ = true; this.disposeInternal(); } } diff --git a/src/ol/VectorImageTile.js b/src/ol/VectorImageTile.js index 85ad648f50..a075fa0699 100644 --- a/src/ol/VectorImageTile.js +++ b/src/ol/VectorImageTile.js @@ -143,8 +143,7 @@ class VectorImageTile extends Tile { * @inheritDoc */ disposeInternal() { - this.state = TileState.ABORT; - this.changed(); + this.setState(TileState.ABORT); for (let i = 0, ii = this.tileKeys.length; i < ii; ++i) { const sourceTileKey = this.tileKeys[i]; @@ -176,6 +175,14 @@ class VectorImageTile extends Tile { return this.context_[key]; } + /** + * @param {import("./layer/Layer.js").default} layer Layer. + * @return {boolean} Tile has a rendering context for the given layer. + */ + hasContext(layer) { + return getUid(layer) in this.context_; + } + /** * Get the Canvas for this tile. * @param {import("./layer/Layer.js").default} layer Layer. @@ -262,7 +269,7 @@ class VectorImageTile extends Tile { }.bind(this)); } if (leftToLoad - Object.keys(errorSourceTiles).length == 0) { - setTimeout(this.finishLoading_.bind(this), 0); + setTimeout(this.finishLoading_.bind(this), 16); } } diff --git a/src/ol/VectorTile.js b/src/ol/VectorTile.js index 3e64403891..e7ae5f0acf 100644 --- a/src/ol/VectorTile.js +++ b/src/ol/VectorTile.js @@ -1,7 +1,6 @@ /** * @module ol/VectorTile */ -import {containsExtent} from './extent.js'; import Tile from './Tile.js'; import TileState from './TileState.js'; @@ -147,30 +146,6 @@ class VectorTile extends Tile { return this.executorGroups_[layerId + ',' + key]; } - /** - * Get the best matching lower resolution replay group for a given zoom and extent. - * @param {string} layerId UID of the layer. - * @param {number} zoom Zoom. - * @param {import("./extent").Extent} extent Extent. - * @return {import("./render/canvas/ExecutorGroup.js").default} Executor groups. - */ - getLowResExecutorGroup(layerId, zoom, extent) { - let bestZoom = 0; - let replayGroup = null; - for (const key in this.executorGroups_) { - const keyData = key.split(','); - const candidateZoom = Number(keyData[1]); - if (keyData[0] === layerId && candidateZoom <= zoom) { - const candidate = this.executorGroups_[key]; - if (containsExtent(candidate.getMaxExtent(), extent) && candidateZoom > bestZoom) { - replayGroup = candidate; - bestZoom = candidateZoom; - } - } - } - return replayGroup; - } - /** * @inheritDoc */ diff --git a/src/ol/render/canvas/ExecutorGroup.js b/src/ol/render/canvas/ExecutorGroup.js index 36d921921d..94b8022adc 100644 --- a/src/ol/render/canvas/ExecutorGroup.js +++ b/src/ol/render/canvas/ExecutorGroup.js @@ -280,13 +280,6 @@ class ExecutorGroup { return flatClipCoords; } - /** - * @return {import("../../extent.js").Extent} The extent of the replay group. - */ - getMaxExtent() { - return this.maxExtent_; - } - /** * @param {number|undefined} zIndex Z index. * @param {import("./BuilderType.js").default} builderType Builder type. diff --git a/src/ol/renderer/Layer.js b/src/ol/renderer/Layer.js index 3d20b415ac..3dd5682626 100644 --- a/src/ol/renderer/Layer.js +++ b/src/ol/renderer/Layer.js @@ -48,6 +48,18 @@ class LayerRenderer extends Observable { return abstract(); } + /** + * @param {Object>} tiles Lookup of loaded tiles by zoom level. + * @param {number} zoom Zoom level. + * @param {import("../Tile.js").default} tile Tile. + */ + loadedTileCallback(tiles, zoom, tile) { + if (!tiles[zoom]) { + tiles[zoom] = {}; + } + tiles[zoom][tile.tileCoord.toString()] = tile; + } + /** * Create a function that adds loaded tiles to the tile lookup. * @param {import("../source/Tile.js").default} source Tile source. @@ -63,20 +75,13 @@ class LayerRenderer extends Observable { * @param {number} zoom Zoom level. * @param {import("../TileRange.js").default} tileRange Tile range. * @return {boolean} The tile range is fully loaded. + * @this {LayerRenderer} */ function(zoom, tileRange) { - /** - * @param {import("../Tile.js").default} tile Tile. - */ - function callback(tile) { - if (!tiles[zoom]) { - tiles[zoom] = {}; - } - tiles[zoom][tile.tileCoord.toString()] = tile; - } + const callback = this.loadedTileCallback.bind(this, tiles, zoom); return source.forEachLoadedTile(projection, zoom, tileRange, callback); } - ); + ).bind(this); } /** diff --git a/src/ol/renderer/canvas/TileLayer.js b/src/ol/renderer/canvas/TileLayer.js index ef9b0059a6..104ae39ad1 100644 --- a/src/ol/renderer/canvas/TileLayer.js +++ b/src/ol/renderer/canvas/TileLayer.js @@ -65,11 +65,11 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { } /** - * @private + * @protected * @param {import("../../Tile.js").default} tile Tile. * @return {boolean} Tile is drawable. */ - isDrawableTile_(tile) { + isDrawableTile(tile) { const tileLayer = /** @type {import("../../layer/Tile.js").default} */ (this.getLayer()); const tileState = tile.getState(); const useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); @@ -99,7 +99,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { this.newTiles_ = true; } } - if (!this.isDrawableTile_(tile)) { + if (!this.isDrawableTile(tile)) { tile = tile.getInterimTile(); } return tile; @@ -177,7 +177,7 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer { for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { const tile = this.getTile(z, x, y, pixelRatio, projection); - if (this.isDrawableTile_(tile)) { + if (this.isDrawableTile(tile)) { const uid = getUid(this); if (tile.getState() == TileState.LOADED) { tilesToDrawByZ[z][tile.tileCoord.toString()] = tile; diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index 4390579207..c788a83788 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -3,6 +3,7 @@ */ import {getUid} from '../../util.js'; import {createCanvasContext2D} from '../../dom.js'; +import {getValues} from '../../obj.js'; import TileState from '../../TileState.js'; import ViewHint from '../../ViewHint.js'; import {listen, unlisten, unlistenByKey} from '../../events.js'; @@ -124,9 +125,15 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { /** * @private - * @type {Object} + * @type {Array} */ - this.tilesToPrepare_ = null; + this.tilesWithoutImage_ = null; + + /** + * @private + * @type {Object= 16) { - break; - } - const args = this.tilesToPrepare_[key]; - delete this.tilesToPrepare_[key]; - const tile = args[0]; - if (!tile.disposed) { - frameState.animate = true; - this.renderTileImage_.apply(this, args); - tile.setState(TileState.LOADED); - } - } - if (Object.keys(this.tilesToPrepare_).length > 0) { - frameState.animate = true; - } else { - this.tilesToPrepare_ = null; - } - } + this.renderMissingTileImages_(hifi, frameState); return this.container_; } + renderMissingTileImages_(hifi, frameState) { + if (hifi) { + while (this.tilesWithoutImage_.length && Date.now() - frameState.time < 100) { + const tile = this.tilesWithoutImage_.pop(); + frameState.animate = true; + this.renderTileImage_(tile, frameState.pixelRatio, frameState.viewState.projection); + } + } + if (this.tilesWithoutImage_.length) { + frameState.animate = true; + } + } + /** * @param {import("../../Feature.js").FeatureLike} feature Feature. * @param {number} squaredTolerance Squared tolerance. diff --git a/test/spec/ol/disposable.test.js b/test/spec/ol/disposable.test.js index 168446f186..21907b9bbd 100644 --- a/test/spec/ol/disposable.test.js +++ b/test/spec/ol/disposable.test.js @@ -12,17 +12,17 @@ describe('ol.Disposable', function() { }); - describe('#disposed', function() { + describe('#disposed_', function() { it('is initially false', function() { const disposable = new Disposable(); - expect(disposable.disposed).to.be(false); + expect(disposable.disposed_).to.be(false); }); it('is true after a call to dispose', function() { const disposable = new Disposable(); disposable.dispose(); - expect(disposable.disposed).to.be(true); + expect(disposable.disposed_).to.be(true); }); }); diff --git a/test/spec/ol/renderer/canvas/vectortilelayer.test.js b/test/spec/ol/renderer/canvas/vectortilelayer.test.js index 6801a21231..526be8d3e0 100644 --- a/test/spec/ol/renderer/canvas/vectortilelayer.test.js +++ b/test/spec/ol/renderer/canvas/vectortilelayer.test.js @@ -75,8 +75,11 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { tileGrid: createXYZ() }); source.getTile = function() { - arguments[1] = TileState.LOADED; const tile = VectorTileSource.prototype.getTile.apply(source, arguments); + tile.hasContext = function() { + return true; + }; + tile.sourceTilesLoaded = true; tile.setState(TileState.LOADED); return tile; }; @@ -242,9 +245,8 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { sourceTile.getImage = function() { return document.createElement('canvas'); }; - const tileUrlFunction = function() {}; const tile = new VectorImageTile([0, 0, 0], undefined, undefined, undefined, - undefined, [0, 0, 0], undefined, createXYZ(), createXYZ(), undefined, undefined, + undefined, [0, 0, 0], undefined, createXYZ(), createXYZ(), {'0,0,0': sourceTile}, undefined, undefined, undefined, undefined); tile.transition_ = 0; tile.wrappedTileCoord = [0, 0, 0]; @@ -256,6 +258,9 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { return tile; }; const renderer = new CanvasVectorTileLayerRenderer(layer); + renderer.isDrawableTile = function() { + return true; + }; const proj = getProjection('EPSG:3857'); const frameState = { extent: proj.getExtent(),