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.
This commit is contained in:
Tim Schaub
2012-10-10 22:05:55 -06:00
parent e83292fb0d
commit f3b7c2384d
6 changed files with 73 additions and 95 deletions
+2 -51
View File
@@ -8,7 +8,6 @@ goog.provide('ol.MapProperty');
goog.provide('ol.RendererHint'); goog.provide('ol.RendererHint');
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.async.AnimationDelay');
goog.require('goog.debug.Logger'); goog.require('goog.debug.Logger');
goog.require('goog.dispose'); goog.require('goog.dispose');
goog.require('goog.dom'); goog.require('goog.dom');
@@ -224,27 +223,6 @@ ol.Map = function(mapOptions) {
new mapOptionsInternal.rendererConstructor(this.viewport_, this); new mapOptionsInternal.rendererConstructor(this.viewport_, this);
this.registerDisposable(this.renderer_); 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 * @private
*/ */
@@ -656,37 +634,10 @@ ol.Map.prototype.recalculateTransforms_ = function() {
/** /**
* Render the map. Map rendering will be called with requestAnimationFrame * Render the map.
* 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.
*/ */
ol.Map.prototype.render = function(opt_force) { ol.Map.prototype.render = function() {
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;
this.renderer_.render(); this.renderer_.render();
if (goog.DEBUG) {
this.logger.info('postrender');
}
this.dispatchEvent(ol.MapEventType.POSTRENDER);
}; };
+13 -25
View File
@@ -135,11 +135,7 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) {
*/ */
ol.renderer.dom.Map.prototype.handleCenterChanged = function() { ol.renderer.dom.Map.prototype.handleCenterChanged = function() {
goog.base(this, 'handleCenterChanged'); goog.base(this, 'handleCenterChanged');
var map = this.getMap(); this.render();
if (!map.isDef()) {
return;
}
map.render();
}; };
@@ -148,11 +144,7 @@ ol.renderer.dom.Map.prototype.handleCenterChanged = function() {
*/ */
ol.renderer.dom.Map.prototype.handleResolutionChanged = function() { ol.renderer.dom.Map.prototype.handleResolutionChanged = function() {
goog.base(this, 'handleResolutionChanged'); goog.base(this, 'handleResolutionChanged');
var map = this.getMap(); this.render();
if (!map.isDef()) {
return;
}
map.render();
}; };
@@ -161,10 +153,7 @@ ol.renderer.dom.Map.prototype.handleResolutionChanged = function() {
*/ */
ol.renderer.dom.Map.prototype.handleRotationChanged = function() { ol.renderer.dom.Map.prototype.handleRotationChanged = function() {
var map = this.getMap(); var map = this.getMap();
if (!map.isDef()) { this.render();
return;
}
map.render();
}; };
@@ -173,11 +162,7 @@ ol.renderer.dom.Map.prototype.handleRotationChanged = function() {
*/ */
ol.renderer.dom.Map.prototype.handleSizeChanged = function() { ol.renderer.dom.Map.prototype.handleSizeChanged = function() {
goog.base(this, 'handleSizeChanged'); goog.base(this, 'handleSizeChanged');
var map = this.getMap(); this.render();
if (!map.isDef()) {
return;
}
map.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 * Render the map. Sets up the layers pane on first render and adjusts its
* position as needed on subsequent calls. * position as needed on subsequent calls.
*/ */
ol.renderer.dom.Map.prototype.render = function() { ol.renderer.dom.Map.prototype.renderFrame = function() {
var map = this.getMap();
if (!map.isDef()) {
return;
}
this.beforeRenderFrame();
var map = this.getMap();
var mapCenter = map.getCenter(); var mapCenter = map.getCenter();
var mapSize = map.getSize(); var mapSize = map.getSize();
var mapResolution = map.getResolution(); var mapResolution = map.getResolution();
@@ -226,7 +210,11 @@ ol.renderer.dom.Map.prototype.render = function() {
this.renderedRotation_ = mapRotation; this.renderedRotation_ = mapRotation;
this.renderedSize_ = mapSize; this.renderedSize_ = mapSize;
goog.base(this, 'render'); this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
layerRenderer.render();
});
this.afterRenderFrame();
}; };
+1 -3
View File
@@ -102,9 +102,7 @@ ol.renderer.dom.TileLayer.prototype.handleTileChange_ = function(event) {
ol.renderer.dom.TileLayer.prototype.render = function() { ol.renderer.dom.TileLayer.prototype.render = function() {
var map = this.getMap(); var map = this.getMap();
if (!map.isDef()) {
return;
}
var mapExtent = /** @type {!ol.Extent} */ map.getRotatedExtent(); var mapExtent = /** @type {!ol.Extent} */ map.getRotatedExtent();
var mapResolution = /** @type {number} */ map.getResolution(); var mapResolution = /** @type {number} */ map.getResolution();
var resolutionChanged = (mapResolution !== this.renderedMapResolution_); var resolutionChanged = (mapResolution !== this.renderedMapResolution_);
+50 -3
View File
@@ -1,6 +1,7 @@
goog.provide('ol.renderer.Map'); goog.provide('ol.renderer.Map');
goog.require('goog.Disposable'); goog.require('goog.Disposable');
goog.require('goog.async.AnimationDelay');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.vec.Mat4'); goog.require('goog.vec.Mat4');
@@ -58,6 +59,27 @@ ol.renderer.Map = function(container, map) {
*/ */
this.matricesDirty_ = true; 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 * @private
* @type {Array.<number>} * @type {Array.<number>}
@@ -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. * @return {boolean} Can rotate.
*/ */
@@ -309,12 +349,19 @@ ol.renderer.Map.prototype.removeLayerRenderer = function(layer) {
* Render. * Render.
*/ */
ol.renderer.Map.prototype.render = function() { ol.renderer.Map.prototype.render = function() {
this.forEachReadyVisibleLayer(function(layer, layerRenderer) { if (!this.pendingRender_ && this.getMap().isDef()) {
layerRenderer.render(); this.pendingRender_ = true;
}); this.delayedRender_.start();
}
}; };
/**
* Render the map.
*/
ol.renderer.Map.prototype.renderFrame = goog.abstractMethod;
/** /**
* @param {ol.layer.Layer} layer Layer. * @param {ol.layer.Layer} layer Layer.
* @param {ol.renderer.Layer} layerRenderer Layer renderer. * @param {ol.renderer.Layer} layerRenderer Layer renderer.
+4 -12
View File
@@ -548,11 +548,9 @@ ol.renderer.webgl.Map.prototype.removeLayerRenderer = function(layer) {
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.renderer.webgl.Map.prototype.render = function() { ol.renderer.webgl.Map.prototype.renderFrame = function() {
if (!this.getMap().isDef()) { this.beforeRenderFrame();
return;
}
var size = /** @type {ol.Size} */ this.getMap().getSize(); var size = /** @type {ol.Size} */ this.getMap().getSize();
if (!this.canvasSize_.equals(size)) { if (!this.canvasSize_.equals(size)) {
@@ -561,11 +559,8 @@ ol.renderer.webgl.Map.prototype.render = function() {
this.canvasSize_ = size; this.canvasSize_ = size;
} }
var rerender = false;
this.forEachReadyVisibleLayer(function(layer, layerRenderer) { this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
if (layerRenderer.render()) { layerRenderer.render();
rerender = true;
}
}); });
var gl = this.getGL(); var gl = this.getGL();
@@ -628,10 +623,7 @@ ol.renderer.webgl.Map.prototype.render = function() {
gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4); gl.drawArrays(goog.webgl.TRIANGLE_STRIP, 0, 4);
}, this); }, this);
if (rerender) { this.afterRenderFrame();
this.getMap().render();
}
}; };
+3 -1
View File
@@ -526,6 +526,8 @@ ol.renderer.webgl.TileLayer.prototype.render = function() {
-0.5, -0.5,
0); 0);
return rerender; if (rerender) {
mapRenderer.render();
}
}; };