From fc6f12d5cdcc4e0f27a004d1298ce8b6cdfa89b6 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 18 Oct 2012 00:09:48 -0400 Subject: [PATCH] Accept a render callback for state generation The map's render method can accept a callback that serves as a state generator. This callback will be called before rendering. Any changes to the map state can be made before rendering takes place (multiple changes will not result in multiple renders). The return from this callback indicates whether the generator is exhausted. --- src/ol/map.js | 13 ++++++-- src/ol/renderer/dom/tilelayer.js | 3 +- src/ol/renderer/map.js | 51 ++++++++++++++++++++++++------ src/ol/renderer/webgl/map.js | 18 +++++------ src/ol/renderer/webgl/tilelayer.js | 2 +- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index 2d3022cb8e..29621033a6 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -635,9 +635,18 @@ ol.Map.prototype.recalculateTransforms_ = function() { /** * Render the map. + * @param {Function|boolean=} opt_callback Function to be called immediately + * before the map is rendered. For renderers that are able to perform + * animations this callback can be used to set various map properties + * without incurring multiple repaints. If the callback returns true, + * another rendering will be scheduled. In this way, the callback works as + * a state generator for an animation. Subsequent calls to render can + * replace or remove this callback (if render is called with no callback). + * If render is called with a boolean, this will retain any pending callback + * (if true) or cancel the pending callback (if false). */ -ol.Map.prototype.render = function() { - this.renderer_.render(); +ol.Map.prototype.render = function(opt_callback) { + this.renderer_.render(opt_callback); }; diff --git a/src/ol/renderer/dom/tilelayer.js b/src/ol/renderer/dom/tilelayer.js index a0e5c69841..6936a6703b 100644 --- a/src/ol/renderer/dom/tilelayer.js +++ b/src/ol/renderer/dom/tilelayer.js @@ -92,7 +92,8 @@ ol.renderer.dom.TileLayer.prototype.removeExtraTiles_ = */ ol.renderer.dom.TileLayer.prototype.handleTileChange_ = function(event) { goog.asserts.assert(event.target.getState() == ol.TileState.LOADED); - this.getMap().render(); + // do not cancel any pending callback + this.getMapRenderer().render(true); }; diff --git a/src/ol/renderer/map.js b/src/ol/renderer/map.js index 0dc1e2e91b..c2e36838b9 100644 --- a/src/ol/renderer/map.js +++ b/src/ol/renderer/map.js @@ -29,6 +29,24 @@ ol.renderer.Map = function(container, map) { */ this.map = map; + /** + * @private + * @type {Function} + */ + this.callback_ = null; + + /** + * @private + * @type {boolean} + */ + this.rendering_ = false; + + /** + * @private + * @type {boolean} + */ + this.pendingRender_ = false; + /** * @protected * @type {Object.} @@ -72,14 +90,6 @@ ol.renderer.Map = function(container, map) { 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.} @@ -129,6 +139,7 @@ ol.renderer.Map.prototype.addLayer = function(layer) { * @protected */ ol.renderer.Map.prototype.afterRenderFrame = function() { + this.rendering_ = false; this.map.dispatchEvent(ol.MapEventType.POSTRENDER); }; @@ -138,7 +149,20 @@ ol.renderer.Map.prototype.afterRenderFrame = function() { * @protected */ ol.renderer.Map.prototype.beforeRenderFrame = function() { + this.rendering_ = true; + var rerender = false; + if (!goog.isNull(this.callback_)) { + // allow state to be set before rendering + rerender = !!this.callback_(); + } this.pendingRender_ = false; + if (rerender) { + // schedule another rendering + this.render(); + } else { + // remove any exhausted callback + this.callback_ = null; + } }; @@ -346,9 +370,16 @@ ol.renderer.Map.prototype.removeLayerRenderer = function(layer) { /** - * Render. + * Render the map. + * @param {Function|boolean=} opt_callback Optional callback. See the + * ol.Map.prototype#render method for a description of this callback. */ -ol.renderer.Map.prototype.render = function() { +ol.renderer.Map.prototype.render = function(opt_callback) { + if (!this.rendering_ && opt_callback !== true) { + // we only replace the callback during calls to render that are + // not triggered during a rendering + this.callback_ = /** @type {Function} */ opt_callback || null; + } if (!this.pendingRender_ && this.getMap().isDef()) { this.pendingRender_ = true; this.delayedRender_.start(); diff --git a/src/ol/renderer/webgl/map.js b/src/ol/renderer/webgl/map.js index c556cc2724..c3c8131603 100644 --- a/src/ol/renderer/webgl/map.js +++ b/src/ol/renderer/webgl/map.js @@ -251,7 +251,7 @@ goog.inherits(ol.renderer.webgl.Map, ol.renderer.Map); ol.renderer.webgl.Map.prototype.addLayer = function(layer) { goog.base(this, 'addLayer', layer); if (layer.getVisible()) { - this.getMap().render(); + this.render(); } }; @@ -417,7 +417,7 @@ ol.renderer.webgl.Map.prototype.handleBackgroundColorChanged = function() { backgroundColor.g / 255, backgroundColor.b / 255, backgroundColor.a / 255); - this.getMap().render(); + this.render(); }; @@ -426,7 +426,7 @@ ol.renderer.webgl.Map.prototype.handleBackgroundColorChanged = function() { */ ol.renderer.webgl.Map.prototype.handleCenterChanged = function() { goog.base(this, 'handleCenterChanged'); - this.getMap().render(); + this.render(); }; @@ -435,7 +435,7 @@ ol.renderer.webgl.Map.prototype.handleCenterChanged = function() { * @protected */ ol.renderer.webgl.Map.prototype.handleLayerRendererChange = function(event) { - this.getMap().render(); + this.render(true); }; @@ -444,7 +444,7 @@ ol.renderer.webgl.Map.prototype.handleLayerRendererChange = function(event) { */ ol.renderer.webgl.Map.prototype.handleResolutionChanged = function() { goog.base(this, 'handleResolutionChanged'); - this.getMap().render(); + this.render(); }; @@ -453,7 +453,7 @@ ol.renderer.webgl.Map.prototype.handleResolutionChanged = function() { */ ol.renderer.webgl.Map.prototype.handleRotationChanged = function() { goog.base(this, 'handleRotationChanged'); - this.getMap().render(); + this.render(); }; @@ -462,7 +462,7 @@ ol.renderer.webgl.Map.prototype.handleRotationChanged = function() { */ ol.renderer.webgl.Map.prototype.handleSizeChanged = function() { goog.base(this, 'handleSizeChanged'); - this.getMap().render(); + this.render(); }; @@ -494,7 +494,7 @@ ol.renderer.webgl.Map.prototype.handleWebGLContextResourced = function() { this.logger.info('WebGLContextResourced'); } this.initializeGL_(); - this.getMap().render(); + this.render(); }; @@ -526,7 +526,7 @@ ol.renderer.webgl.Map.prototype.isImageTextureLoaded = function(image) { ol.renderer.webgl.Map.prototype.removeLayer = function(layer) { goog.base(this, 'removeLayer', layer); if (layer.getVisible()) { - this.getMap().render(); + this.render(); } }; diff --git a/src/ol/renderer/webgl/tilelayer.js b/src/ol/renderer/webgl/tilelayer.js index 4386efb077..f3137ce56d 100644 --- a/src/ol/renderer/webgl/tilelayer.js +++ b/src/ol/renderer/webgl/tilelayer.js @@ -527,7 +527,7 @@ ol.renderer.webgl.TileLayer.prototype.render = function() { 0); if (rerender) { - mapRenderer.render(); + mapRenderer.render(true); } };