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

View File

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

View File

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

View File

@@ -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_);

View File

@@ -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.<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.
*/
@@ -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.

View File

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

View File

@@ -526,6 +526,8 @@ ol.renderer.webgl.TileLayer.prototype.render = function() {
-0.5,
0);
return rerender;
if (rerender) {
mapRenderer.render();
}
};