diff --git a/src/ol/VectorImageTile.js b/src/ol/VectorImageTile.js index e4fd58ceb6..eaa36142c9 100644 --- a/src/ol/VectorImageTile.js +++ b/src/ol/VectorImageTile.js @@ -103,11 +103,17 @@ class VectorImageTile extends Tile { */ this.sourceTileListenerKeys_ = []; + /** + * Use only source tiles that are loaded already + * @type {boolean} + */ + this.useLoadedOnly = zoom != tileCoord[0]; + if (urlTileCoord) { const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord); const resolution = tileGrid.getResolution(zoom); const sourceZ = sourceTileGrid.getZForResolution(resolution); - const useLoadedOnly = zoom != tileCoord[0]; + const useLoadedOnly = this.useLoadedOnly; let loadCount = 0; sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) { let sharedExtent = getIntersection(extent, diff --git a/src/ol/VectorTile.js b/src/ol/VectorTile.js index cac9e59683..3a59e2fce4 100644 --- a/src/ol/VectorTile.js +++ b/src/ol/VectorTile.js @@ -1,6 +1,7 @@ /** * @module ol/VectorTile */ +import {containsExtent} from './extent.js'; import {getUid} from './util.js'; import Tile from './Tile.js'; import TileState from './TileState.js'; @@ -147,6 +148,31 @@ class VectorTile extends Tile { return this.replayGroups_[getUid(layer) + ',' + key]; } + /** + * Get the best matching lower resolution replay group for a given zoom and extent. + * @param {import("./layer/Layer").default} layer Layer. + * @param {number} zoom Zoom. + * @param {import("./extent").Extent} extent Extent. + * @return {import("./render/ReplayGroup.js").default} Replay groups. + */ + getLowResReplayGroup(layer, zoom, extent) { + const layerId = getUid(layer); + let bestZoom = 0; + let replayGroup = null; + for (const key in this.replayGroups_) { + const keyData = key.split(','); + const candidateZoom = Number(keyData[1]); + if (keyData[0] === layerId && candidateZoom <= zoom) { + const candidate = this.replayGroups_[key]; + if (containsExtent(candidate.getMaxExtent(), extent) && candidateZoom > bestZoom) { + replayGroup = candidate; + bestZoom = candidateZoom; + } + } + } + return replayGroup; + } + /** * @inheritDoc */ diff --git a/src/ol/render/canvas/ReplayGroup.js b/src/ol/render/canvas/ReplayGroup.js index 5d055a7cdf..fa7aaaf89d 100644 --- a/src/ol/render/canvas/ReplayGroup.js +++ b/src/ol/render/canvas/ReplayGroup.js @@ -311,6 +311,13 @@ class CanvasReplayGroup extends ReplayGroup { return flatClipCoords; } + /** + * @return {import("../../extent.js").Extent} The extent of the replay group. + */ + getMaxExtent() { + return this.maxExtent_; + } + /** * @inheritDoc */ diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index d25e3ec853..2e608ea9d2 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -156,7 +156,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { const source = /** @type {import("../../source/VectorTile.js").default} */ (layer.getSource()); const sourceTileGrid = source.getTileGrid(); const tileGrid = source.getTileGridForProjection(projection); - const resolution = tileGrid.getResolution(tile.tileCoord[0]); + const zoom = tile.tileCoord[0]; + const resolution = tileGrid.getResolution(zoom); const tileExtent = tile.extent; for (let t = 0, tt = tile.tileKeys.length; t < tt; ++t) { @@ -164,6 +165,14 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { if (sourceTile.getState() != TileState.LOADED) { continue; } + if (tile.useLoadedOnly) { + const lowResReplayGroup = sourceTile.getLowResReplayGroup(layer, zoom, tileExtent); + if (lowResReplayGroup) { + // reuse existing replay if we're rendering an interim tile + sourceTile.setReplayGroup(layer, tile.tileCoord.toString(), lowResReplayGroup); + continue; + } + } const sourceTileCoord = sourceTile.tileCoord; const sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);