Render only when we have time, and not during interaction/animation

This commit is contained in:
ahocevar
2018-11-21 15:30:00 +01:00
parent 82e2a84862
commit 2ce8fa6f10
4 changed files with 58 additions and 20 deletions
+3 -3
View File
@@ -14,15 +14,15 @@ class Disposable {
* @type {boolean} * @type {boolean}
* @private * @private
*/ */
this.disposed_ = false; this.disposed = false;
} }
/** /**
* Clean up. * Clean up.
*/ */
dispose() { dispose() {
if (!this.disposed_) { if (!this.disposed) {
this.disposed_ = true; this.disposed = true;
this.disposeInternal(); this.disposeInternal();
} }
} }
+43 -10
View File
@@ -122,6 +122,12 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
*/ */
this.renderedLayerRevision_; this.renderedLayerRevision_;
/**
* @private
* @type {Object<string, import("../../VectorImageTile").default>}
*/
this.tilesToPrepare_ = null;
/** /**
* @private * @private
* @type {import("../../transform.js").Transform} * @type {import("../../transform.js").Transform}
@@ -151,17 +157,23 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
if (tile.getState() === TileState.IDLE) { if (tile.getState() === TileState.IDLE) {
const key = listen(tile, EventType.CHANGE, function() { const key = listen(tile, EventType.CHANGE, function() {
if (tile.sourceTilesLoaded) { if (tile.sourceTilesLoaded) {
this.createExecutorGroup_(tile, pixelRatio, projection); this.updateExecutorGroup_(tile, pixelRatio, projection);
if (!this.tilesToPrepare_) {
this.tilesToPrepare_ = {};
tile.setState(TileState.LOADED);
} else {
const tileId = getUid(tile);
if (!(tileId in this.tilesToPrepare_)) {
this.tilesToPrepare_[tileId] = [tile, pixelRatio, projection];
}
}
unlistenByKey(key); unlistenByKey(key);
tile.setState(TileState.LOADED);
} }
}.bind(this)); }.bind(this));
} }
if (tile.getState() === TileState.LOADED) { if (tile.getState() === TileState.LOADED) {
this.createExecutorGroup_(tile, pixelRatio, projection); this.updateExecutorGroup_(tile, pixelRatio, projection);
if (this.context) { this.renderTileImage_(tile, pixelRatio, projection);
this.renderTileImage_(tile, pixelRatio, projection);
}
} }
return tile; return tile;
} }
@@ -193,7 +205,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
* @param {import("../../proj/Projection.js").default} projection Projection. * @param {import("../../proj/Projection.js").default} projection Projection.
* @private * @private
*/ */
createExecutorGroup_(tile, pixelRatio, projection) { updateExecutorGroup_(tile, pixelRatio, projection) {
const layer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer()); const layer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer());
const revision = layer.getRevision(); const revision = layer.getRevision();
const renderOrder = /** @type {import("../../render.js").OrderFunction} */ (layer.getRenderOrder()) || null; const renderOrder = /** @type {import("../../render.js").OrderFunction} */ (layer.getRenderOrder()) || null;
@@ -413,7 +425,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
this.declutterTree_.clear(); this.declutterTree_.clear();
} }
const viewHints = frameState.viewHints; const viewHints = frameState.viewHints;
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]); const hifi = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
const tiles = this.renderedTiles; const tiles = this.renderedTiles;
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection); const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
const clips = []; const clips = [];
@@ -460,14 +472,14 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
context.clip(); context.clip();
} }
} }
executorGroup.execute(context, transform, rotation, {}, snapToPixel, replayTypes, declutterReplays); executorGroup.execute(context, transform, rotation, {}, hifi, replayTypes, declutterReplays);
context.restore(); context.restore();
clips.push(currentClip); clips.push(currentClip);
zs.push(currentZ); zs.push(currentZ);
} }
} }
if (declutterReplays) { if (declutterReplays) {
replayDeclutter(declutterReplays, context, rotation, snapToPixel); replayDeclutter(declutterReplays, context, rotation, hifi);
} }
const opacity = layerState.opacity; const opacity = layerState.opacity;
@@ -475,6 +487,27 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
canvas.style.opacity = opacity; canvas.style.opacity = opacity;
} }
if (this.tilesToPrepare_) {
for (const key in this.tilesToPrepare_) {
if (!hifi || Date.now() - frameState.time >= 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;
}
}
return this.container_; return this.container_;
} }
+3 -3
View File
@@ -12,17 +12,17 @@ describe('ol.Disposable', function() {
}); });
describe('#disposed_', function() { describe('#disposed', function() {
it('is initially false', function() { it('is initially false', function() {
const disposable = new Disposable(); 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() { it('is true after a call to dispose', function() {
const disposable = new Disposable(); const disposable = new Disposable();
disposable.dispose(); disposable.dispose();
expect(disposable.disposed_).to.be(true); expect(disposable.disposed).to.be(true);
}); });
}); });
+9 -4
View File
@@ -30,7 +30,7 @@ describe('ol.VectorImageTile', function() {
}); });
}); });
it('sets LOADED state when previously failed source tiles are loaded', function(done) { it('sets sourceTilesLoaded when previously failed source tiles are loaded', function(done) {
const format = new GeoJSON(); const format = new GeoJSON();
const url = 'spec/ol/data/unavailable.json'; const url = 'spec/ol/data/unavailable.json';
let sourceTile; let sourceTile;
@@ -47,7 +47,11 @@ describe('ol.VectorImageTile', function() {
let calls = 0; let calls = 0;
listen(tile, 'change', function(e) { listen(tile, 'change', function(e) {
++calls; ++calls;
expect(tile.getState()).to.be(calls == 2 ? TileState.LOADED : TileState.ERROR); if (calls === 1) {
expect(tile.sourceTilesLoaded).to.be(false);
} else if (calls === 2) {
expect(tile.sourceTilesLoaded).to.be(true);
}
if (calls == 2) { if (calls == 2) {
done(); done();
} else { } else {
@@ -131,7 +135,7 @@ describe('ol.VectorImageTile', function() {
expect(tile.getState()).to.be(TileState.ABORT); expect(tile.getState()).to.be(TileState.ABORT);
}); });
it('#dispose() when loaded', function(done) { it('#dispose() when source tiles are loaded', function(done) {
const format = new GeoJSON(); const format = new GeoJSON();
const url = 'spec/ol/data/point.json'; const url = 'spec/ol/data/point.json';
const tile = new VectorImageTile([0, 0, 0], 0, url, format, const tile = new VectorImageTile([0, 0, 0], 0, url, format,
@@ -142,7 +146,8 @@ describe('ol.VectorImageTile', function() {
tile.load(); tile.load();
listenOnce(tile, 'change', function() { listenOnce(tile, 'change', function() {
expect(tile.getState()).to.be(TileState.LOADED); expect(tile.getState()).to.be(TileState.LOADING);
expect(tile.sourceTilesLoaded).to.be.ok();
expect(tile.loadListenerKeys_.length).to.be(0); expect(tile.loadListenerKeys_.length).to.be(0);
expect(tile.tileKeys.length).to.be(4); expect(tile.tileKeys.length).to.be(4);
tile.dispose(); tile.dispose();