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); } };