Files
openlayers/lib/OpenLayers/Tween.js
ahocevar 9759902dac Fixing API; addressing @mpriour's doc comment
Previously, minFrameRate could not be set as option with the start method.
The tests failed to catch this flaw. Now both the start method and the
tests are fixed.
2012-12-21 21:24:04 +01:00

362 lines
8.7 KiB
JavaScript

/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the 2-clause BSD license.
* See license.txt in the OpenLayers distribution or repository for the
* full text of the license. */
/**
* @requires OpenLayers/BaseTypes/Class.js
* @requires OpenLayers/Animation.js
*/
/**
* Namespace: OpenLayers.Tween
*/
OpenLayers.Tween = OpenLayers.Class({
/**
* APIProperty: easing
* {<OpenLayers.Easing>(Function)} Easing equation used for the animation
* Defaultly set to OpenLayers.Easing.Expo.easeOut
*/
easing: null,
/**
* APIProperty: begin
* {Object} Values to start the animation with
*/
begin: null,
/**
* APIProperty: finish
* {Object} Values to finish the animation with
*/
finish: null,
/**
* APIProperty: duration
* {int} duration of the tween (number of steps)
*/
duration: null,
/**
* APIProperty: callbacks
* {Object} An object with start, eachStep and done properties whose values
* are functions to be call during the animation. They are passed the
* current computed value as argument.
*/
callbacks: null,
/**
* Property: time
* {int} Step counter
*/
time: null,
/**
* APIProperty: minFrameRate
* {Number} The minimum framerate for animations in frames per second. After
* each step, the time spent in the animation is compared to the calculated
* time at this frame rate. If the animation runs longer than the calculated
* time, the next step is skipped. Default is 30.
*/
minFrameRate: null,
/**
* Property: startTime
* {Number} The timestamp of the first execution step. Used for skipping
* frames
*/
startTime: null,
/**
* Property: animationId
* {int} Loop id returned by OpenLayers.Animation.start
*/
animationId: null,
/**
* Property: playing
* {Boolean} Tells if the easing is currently playing
*/
playing: false,
/**
* Constructor: OpenLayers.Tween
* Creates a Tween.
*
* Parameters:
* easing - {<OpenLayers.Easing>(Function)} easing function method to use
*/
initialize: function(easing) {
this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
},
/**
* APIMethod: start
* Plays the Tween, and calls the callback method on each step
*
* Parameters:
* begin - {Object} values to start the animation with
* finish - {Object} values to finish the animation with
* duration - {int} duration of the tween (number of steps)
* options - {Object} hash of options (callbacks (start, eachStep, done),
* minFrameRate)
*/
start: function(begin, finish, duration, options) {
this.playing = true;
this.begin = begin;
this.finish = finish;
this.duration = duration;
this.callbacks = options.callbacks;
this.minFrameRate = options.minFrameRate || 30;
this.time = 0;
this.startTime = new Date().getTime();
OpenLayers.Animation.stop(this.animationId);
this.animationId = null;
if (this.callbacks && this.callbacks.start) {
this.callbacks.start.call(this, this.begin);
}
this.animationId = OpenLayers.Animation.start(
OpenLayers.Function.bind(this.play, this)
);
},
/**
* APIMethod: stop
* Stops the Tween, and calls the done callback
* Doesn't do anything if animation is already finished
*/
stop: function() {
if (!this.playing) {
return;
}
if (this.callbacks && this.callbacks.done) {
this.callbacks.done.call(this, this.finish);
}
OpenLayers.Animation.stop(this.animationId);
this.animationId = null;
this.playing = false;
},
/**
* Method: play
* Calls the appropriate easing method
*/
play: function() {
var value = {};
for (var i in this.begin) {
var b = this.begin[i];
var f = this.finish[i];
if (b == null || f == null || isNaN(b) || isNaN(f)) {
throw new TypeError('invalid value for Tween');
}
var c = f - b;
value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
}
this.time++;
if (this.callbacks && this.callbacks.eachStep) {
// skip frames if frame rate drops below threshold
if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {
this.callbacks.eachStep.call(this, value);
}
}
if (this.time > this.duration) {
this.stop();
}
},
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Tween"
});
/**
* Namespace: OpenLayers.Easing
*
* Credits:
* Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
*/
OpenLayers.Easing = {
/**
* Create empty functions for all easing methods.
*/
CLASS_NAME: "OpenLayers.Easing"
};
/**
* Namespace: OpenLayers.Easing.Linear
*/
OpenLayers.Easing.Linear = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeIn: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeOut: function(t, b, c, d) {
return c*t/d + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeInOut: function(t, b, c, d) {
return c*t/d + b;
},
CLASS_NAME: "OpenLayers.Easing.Linear"
};
/**
* Namespace: OpenLayers.Easing.Expo
*/
OpenLayers.Easing.Expo = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeIn: function(t, b, c, d) {
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeOut: function(t, b, c, d) {
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeInOut: function(t, b, c, d) {
if (t==0) return b;
if (t==d) return b+c;
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
},
CLASS_NAME: "OpenLayers.Easing.Expo"
};
/**
* Namespace: OpenLayers.Easing.Quad
*/
OpenLayers.Easing.Quad = {
/**
* Function: easeIn
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeIn: function(t, b, c, d) {
return c*(t/=d)*t + b;
},
/**
* Function: easeOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeOut: function(t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
},
/**
* Function: easeInOut
*
* Parameters:
* t - {Float} time
* b - {Float} beginning position
* c - {Float} total change
* d - {Float} duration of the transition
*
* Returns:
* {Float}
*/
easeInOut: function(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
CLASS_NAME: "OpenLayers.Easing.Quad"
};