From f3b7c2384d921cfb0d70869b210eadb36f3654d9 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 10 Oct 2012 22:05:55 -0600 Subject: [PATCH] Leaving animation entirely up to the renderers With this change, the map knows nothing of animation. Different renderers may behave differently when their render method is called. A PDF renderer (thought experiment at this point) might immediately render to a file. The dom based renderers schedule a repaint for the next animation frame or in a timeout depending on capabilities - in either case, setting multiple map properties will *not* result in multiple reflow/repaints. --- src/ol/map.js | 53 ++---------------------------- src/ol/renderer/dom/map.js | 38 ++++++++------------- src/ol/renderer/dom/tilelayer.js | 4 +-- src/ol/renderer/map.js | 53 ++++++++++++++++++++++++++++-- src/ol/renderer/webgl/map.js | 16 +++------ src/ol/renderer/webgl/tilelayer.js | 4 ++- 6 files changed, 73 insertions(+), 95 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index 1ab7be113c..2d3022cb8e 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -8,7 +8,6 @@ goog.provide('ol.MapProperty'); goog.provide('ol.RendererHint'); goog.require('goog.array'); -goog.require('goog.async.AnimationDelay'); goog.require('goog.debug.Logger'); goog.require('goog.dispose'); goog.require('goog.dom'); @@ -224,27 +223,6 @@ ol.Map = function(mapOptions) { new mapOptionsInternal.rendererConstructor(this.viewport_, this); this.registerDisposable(this.renderer_); - /** - * Calls to this.delayedRender_.start take advantage of requestAnimationFrame - * (and friends) where available. The provided listener is called once in - * the next available frame after the start method is called. A call to stop - * will cancel the animation. - * - * @type {goog.async.AnimationDelay} - * @private - */ - this.delayedRender_ = new goog.async.AnimationDelay( - this.renderFrame_, null, this); - this.registerDisposable(this.delayedRender_); - - /** - * Flag to indicate whether this.delayedRender_.start has been called. - * - * @type {boolean} - * @private - */ - this.pendingRender_ = false; - /** * @private */ @@ -656,37 +634,10 @@ ol.Map.prototype.recalculateTransforms_ = function() { /** - * Render the map. Map rendering will be called with requestAnimationFrame - * or in a timeout depending on the environment. - * - * @param {boolean=} opt_force Render immediately. If called with force, - * rendering will occur before method returns. If called without force, - * method will return before rendering occurs. + * Render the map. */ -ol.Map.prototype.render = function(opt_force) { - if (opt_force) { - this.delayedRender_.stop(); - this.renderFrame_(); - } else if (!this.pendingRender_) { - this.pendingRender_ = true; - this.delayedRender_.start(); - } -}; - - -/** - * @private - */ -ol.Map.prototype.renderFrame_ = function() { - if (goog.DEBUG) { - this.logger.info('renderFrame_'); - } - this.pendingRender_ = false; +ol.Map.prototype.render = function() { this.renderer_.render(); - if (goog.DEBUG) { - this.logger.info('postrender'); - } - this.dispatchEvent(ol.MapEventType.POSTRENDER); }; diff --git a/src/ol/renderer/dom/map.js b/src/ol/renderer/dom/map.js index 875c48c5e3..d547041cbd 100644 --- a/src/ol/renderer/dom/map.js +++ b/src/ol/renderer/dom/map.js @@ -135,11 +135,7 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { */ ol.renderer.dom.Map.prototype.handleCenterChanged = function() { goog.base(this, 'handleCenterChanged'); - var map = this.getMap(); - if (!map.isDef()) { - return; - } - map.render(); + this.render(); }; @@ -148,11 +144,7 @@ ol.renderer.dom.Map.prototype.handleCenterChanged = function() { */ ol.renderer.dom.Map.prototype.handleResolutionChanged = function() { goog.base(this, 'handleResolutionChanged'); - var map = this.getMap(); - if (!map.isDef()) { - return; - } - map.render(); + this.render(); }; @@ -161,10 +153,7 @@ ol.renderer.dom.Map.prototype.handleResolutionChanged = function() { */ ol.renderer.dom.Map.prototype.handleRotationChanged = function() { var map = this.getMap(); - if (!map.isDef()) { - return; - } - map.render(); + this.render(); }; @@ -173,11 +162,7 @@ ol.renderer.dom.Map.prototype.handleRotationChanged = function() { */ ol.renderer.dom.Map.prototype.handleSizeChanged = function() { goog.base(this, 'handleSizeChanged'); - var map = this.getMap(); - if (!map.isDef()) { - return; - } - map.render(); + this.render(); }; @@ -185,12 +170,11 @@ ol.renderer.dom.Map.prototype.handleSizeChanged = function() { * Render the map. Sets up the layers pane on first render and adjusts its * position as needed on subsequent calls. */ -ol.renderer.dom.Map.prototype.render = function() { - var map = this.getMap(); - if (!map.isDef()) { - return; - } +ol.renderer.dom.Map.prototype.renderFrame = function() { + this.beforeRenderFrame(); + + var map = this.getMap(); var mapCenter = map.getCenter(); var mapSize = map.getSize(); var mapResolution = map.getResolution(); @@ -226,7 +210,11 @@ ol.renderer.dom.Map.prototype.render = function() { this.renderedRotation_ = mapRotation; this.renderedSize_ = mapSize; - goog.base(this, 'render'); + this.forEachReadyVisibleLayer(function(layer, layerRenderer) { + layerRenderer.render(); + }); + + this.afterRenderFrame(); }; diff --git a/src/ol/renderer/dom/tilelayer.js b/src/ol/renderer/dom/tilelayer.js index 6c2e474cb0..a0e5c69841 100644 --- a/src/ol/renderer/dom/tilelayer.js +++ b/src/ol/renderer/dom/tilelayer.js @@ -102,9 +102,7 @@ ol.renderer.dom.TileLayer.prototype.handleTileChange_ = function(event) { ol.renderer.dom.TileLayer.prototype.render = function() { var map = this.getMap(); - if (!map.isDef()) { - return; - } + var mapExtent = /** @type {!ol.Extent} */ map.getRotatedExtent(); var mapResolution = /** @type {number} */ map.getResolution(); var resolutionChanged = (mapResolution !== this.renderedMapResolution_); diff --git a/src/ol/renderer/map.js b/src/ol/renderer/map.js index 371091df17..0dc1e2e91b 100644 --- a/src/ol/renderer/map.js +++ b/src/ol/renderer/map.js @@ -1,6 +1,7 @@ goog.provide('ol.renderer.Map'); goog.require('goog.Disposable'); +goog.require('goog.async.AnimationDelay'); goog.require('goog.events'); goog.require('goog.vec.Mat4'); @@ -58,6 +59,27 @@ ol.renderer.Map = function(container, map) { */ this.matricesDirty_ = true; + /** + * Calls to this.delayedRender_.start take advantage of requestAnimationFrame + * (and friends) where available. The provided listener is called once in + * the next available frame after the start method is called. A call to stop + * will cancel the animation. + * + * @type {goog.async.AnimationDelay} + * @private + */ + this.delayedRender_ = new goog.async.AnimationDelay( + this.renderFrame, null, this); + this.registerDisposable(this.delayedRender_); + + /** + * Flag to indicate whether this.delayedRender_.start has been called. + * + * @type {boolean} + * @private + */ + this.pendingRender_ = false; + /** * @private * @type {Array.} @@ -102,6 +124,24 @@ ol.renderer.Map.prototype.addLayer = function(layer) { }; +/** + * Must be called by subclasses after renderFrame completes. + * @protected + */ +ol.renderer.Map.prototype.afterRenderFrame = function() { + this.map.dispatchEvent(ol.MapEventType.POSTRENDER); +}; + + +/** + * Must be called by subclasses before renderFrame executes. + * @protected + */ +ol.renderer.Map.prototype.beforeRenderFrame = function() { + this.pendingRender_ = false; +}; + + /** * @return {boolean} Can rotate. */ @@ -309,12 +349,19 @@ ol.renderer.Map.prototype.removeLayerRenderer = function(layer) { * Render. */ ol.renderer.Map.prototype.render = function() { - this.forEachReadyVisibleLayer(function(layer, layerRenderer) { - layerRenderer.render(); - }); + if (!this.pendingRender_ && this.getMap().isDef()) { + this.pendingRender_ = true; + this.delayedRender_.start(); + } }; +/** + * Render the map. + */ +ol.renderer.Map.prototype.renderFrame = goog.abstractMethod; + + /** * @param {ol.layer.Layer} layer Layer. * @param {ol.renderer.Layer} layerRenderer Layer renderer. diff --git a/src/ol/renderer/webgl/map.js b/src/ol/renderer/webgl/map.js index fccdbddc64..c556cc2724 100644 --- a/src/ol/renderer/webgl/map.js +++ b/src/ol/renderer/webgl/map.js @@ -548,11 +548,9 @@ ol.renderer.webgl.Map.prototype.removeLayerRenderer = function(layer) { /** * @inheritDoc */ -ol.renderer.webgl.Map.prototype.render = function() { +ol.renderer.webgl.Map.prototype.renderFrame = function() { - if (!this.getMap().isDef()) { - return; - } + this.beforeRenderFrame(); var size = /** @type {ol.Size} */ this.getMap().getSize(); if (!this.canvasSize_.equals(size)) { @@ -561,11 +559,8 @@ ol.renderer.webgl.Map.prototype.render = function() { this.canvasSize_ = size; } - var rerender = false; this.forEachReadyVisibleLayer(function(layer, layerRenderer) { - if (layerRenderer.render()) { - rerender = true; - } + layerRenderer.render(); }); var gl = this.getGL(); @@ -628,10 +623,7 @@ ol.renderer.webgl.Map.prototype.render = function() { gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); }, this); - if (rerender) { - this.getMap().render(); - } - + this.afterRenderFrame(); }; diff --git a/src/ol/renderer/webgl/tilelayer.js b/src/ol/renderer/webgl/tilelayer.js index 180d24c196..4386efb077 100644 --- a/src/ol/renderer/webgl/tilelayer.js +++ b/src/ol/renderer/webgl/tilelayer.js @@ -526,6 +526,8 @@ ol.renderer.webgl.TileLayer.prototype.render = function() { -0.5, 0); - return rerender; + if (rerender) { + mapRenderer.render(); + } };