476 lines
11 KiB
JavaScript
476 lines
11 KiB
JavaScript
/*
|
|
Copyright (c) 2004-2006, The Dojo Foundation
|
|
All Rights Reserved.
|
|
|
|
Licensed under the Academic Free License version 2.1 or above OR the
|
|
modified BSD license. For more information on Dojo licensing, see:
|
|
|
|
http://dojotoolkit.org/community/licensing.shtml
|
|
*/
|
|
|
|
dojo.provide("dojo.lfx.Animation");
|
|
dojo.provide("dojo.lfx.Line");
|
|
|
|
dojo.require("dojo.lang.func");
|
|
|
|
/*
|
|
Animation package based on Dan Pupius' work: http://pupius.co.uk/js/Toolkit.Drawing.js
|
|
*/
|
|
dojo.lfx.Line = function(start, end){
|
|
this.start = start;
|
|
this.end = end;
|
|
if(dojo.lang.isArray(start)){
|
|
var diff = [];
|
|
dojo.lang.forEach(this.start, function(s,i){
|
|
diff[i] = this.end[i] - s;
|
|
}, this);
|
|
|
|
this.getValue = function(/*float*/ n){
|
|
var res = [];
|
|
dojo.lang.forEach(this.start, function(s, i){
|
|
res[i] = (diff[i] * n) + s;
|
|
}, this);
|
|
return res;
|
|
}
|
|
}else{
|
|
var diff = end - start;
|
|
|
|
this.getValue = function(/*float*/ n){
|
|
// summary: returns the point on the line
|
|
// n: a floating point number greater than 0 and less than 1
|
|
return (diff * n) + this.start;
|
|
}
|
|
}
|
|
}
|
|
|
|
dojo.lfx.easeIn = function(n){
|
|
// summary: returns the point on an easing curve
|
|
// n: a floating point number greater than 0 and less than 1
|
|
return Math.pow(n, 3);
|
|
}
|
|
|
|
dojo.lfx.easeOut = function(n){
|
|
// summary: returns the point on the line
|
|
// n: a floating point number greater than 0 and less than 1
|
|
return ( 1 - Math.pow(1 - n, 3) );
|
|
}
|
|
|
|
dojo.lfx.easeInOut = function(n){
|
|
// summary: returns the point on the line
|
|
// n: a floating point number greater than 0 and less than 1
|
|
return ( (3 * Math.pow(n, 2)) - (2 * Math.pow(n, 3)) );
|
|
}
|
|
|
|
dojo.lfx.IAnimation = function(){}
|
|
dojo.lang.extend(dojo.lfx.IAnimation, {
|
|
// public properties
|
|
curve: null,
|
|
duration: 1000,
|
|
easing: null,
|
|
repeatCount: 0,
|
|
rate: 25,
|
|
|
|
// events
|
|
handler: null,
|
|
beforeBegin: null,
|
|
onBegin: null,
|
|
onAnimate: null,
|
|
onEnd: null,
|
|
onPlay: null,
|
|
onPause: null,
|
|
onStop: null,
|
|
|
|
// public methods
|
|
play: null,
|
|
pause: null,
|
|
stop: null,
|
|
|
|
fire: function(evt, args){
|
|
if(this[evt]){
|
|
this[evt].apply(this, (args||[]));
|
|
}
|
|
},
|
|
|
|
// private properties
|
|
_active: false,
|
|
_paused: false
|
|
});
|
|
|
|
dojo.lfx.Animation = function(/*Object*/ handlers, /*int*/ duration, /*Array*/ curve, /*function*/ easing, /*int*/ repeatCount, /*int*/ rate){
|
|
// summary
|
|
// a generic animation object that fires callbacks into it's handlers
|
|
// object at various states
|
|
// handlers
|
|
// object {
|
|
// handler: function(){},
|
|
// onstart: function(){},
|
|
// onstop: function(){},
|
|
// onanimate: function(){}
|
|
// }
|
|
dojo.lfx.IAnimation.call(this);
|
|
if(dojo.lang.isNumber(handlers)||(!handlers && duration.getValue)){
|
|
// no handlers argument:
|
|
rate = repeatCount;
|
|
repeatCount = easing;
|
|
easing = curve;
|
|
curve = duration;
|
|
duration = handlers;
|
|
handlers = null;
|
|
}else if(handlers.getValue||dojo.lang.isArray(handlers)){
|
|
// no handlers or duration:
|
|
rate = easing;
|
|
repeatCount = curve;
|
|
easing = duration;
|
|
curve = handlers;
|
|
duration = null;
|
|
handlers = null;
|
|
}
|
|
if(dojo.lang.isArray(curve)){
|
|
this.curve = new dojo.lfx.Line(curve[0], curve[1]);
|
|
}else{
|
|
this.curve = curve;
|
|
}
|
|
if(duration != null && duration > 0){ this.duration = duration; }
|
|
if(repeatCount){ this.repeatCount = repeatCount; }
|
|
if(rate){ this.rate = rate; }
|
|
if(handlers){
|
|
this.handler = handlers.handler;
|
|
this.beforeBegin = handlers.beforeBegin;
|
|
this.onBegin = handlers.onBegin;
|
|
this.onEnd = handlers.onEnd;
|
|
this.onPlay = handlers.onPlay;
|
|
this.onPause = handlers.onPause;
|
|
this.onStop = handlers.onStop;
|
|
this.onAnimate = handlers.onAnimate;
|
|
}
|
|
if(easing && dojo.lang.isFunction(easing)){
|
|
this.easing=easing;
|
|
}
|
|
}
|
|
dojo.inherits(dojo.lfx.Animation, dojo.lfx.IAnimation);
|
|
dojo.lang.extend(dojo.lfx.Animation, {
|
|
// "private" properties
|
|
_startTime: null,
|
|
_endTime: null,
|
|
_timer: null,
|
|
_percent: 0,
|
|
_startRepeatCount: 0,
|
|
|
|
// public methods
|
|
play: function(delay, gotoStart){
|
|
if(gotoStart){
|
|
clearTimeout(this._timer);
|
|
this._active = false;
|
|
this._paused = false;
|
|
this._percent = 0;
|
|
}else if(this._active && !this._paused){
|
|
return this;
|
|
}
|
|
|
|
this.fire("handler", ["beforeBegin"]);
|
|
this.fire("beforeBegin");
|
|
|
|
if(delay > 0){
|
|
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
|
|
return this;
|
|
}
|
|
|
|
this._startTime = new Date().valueOf();
|
|
if(this._paused){
|
|
this._startTime -= (this.duration * this._percent / 100);
|
|
}
|
|
this._endTime = this._startTime + this.duration;
|
|
|
|
this._active = true;
|
|
this._paused = false;
|
|
|
|
var step = this._percent / 100;
|
|
var value = this.curve.getValue(step);
|
|
if( this._percent == 0 ) {
|
|
if(!this._startRepeatCount) {
|
|
this._startRepeatCount = this.repeatCount;
|
|
}
|
|
this.fire("handler", ["begin", value]);
|
|
this.fire("onBegin", [value]);
|
|
}
|
|
|
|
this.fire("handler", ["play", value]);
|
|
this.fire("onPlay", [value]);
|
|
|
|
this._cycle();
|
|
return this;
|
|
},
|
|
|
|
pause: function() {
|
|
clearTimeout(this._timer);
|
|
if(!this._active){ return this; }
|
|
this._paused = true;
|
|
var value = this.curve.getValue(this._percent / 100);
|
|
this.fire("handler", ["pause", value]);
|
|
this.fire("onPause", [value]);
|
|
return this;
|
|
},
|
|
|
|
gotoPercent: function(pct, andPlay) {
|
|
clearTimeout(this._timer);
|
|
this._active = true;
|
|
this._paused = true;
|
|
this._percent = pct;
|
|
if( andPlay ) { this.play(); }
|
|
},
|
|
|
|
stop: function(gotoEnd) {
|
|
clearTimeout(this._timer);
|
|
var step = this._percent / 100;
|
|
if( gotoEnd ) {
|
|
step = 1;
|
|
}
|
|
var value = this.curve.getValue(step);
|
|
this.fire("handler", ["stop", value]);
|
|
this.fire("onStop", [value]);
|
|
this._active = false;
|
|
this._paused = false;
|
|
return this;
|
|
},
|
|
|
|
status: function() {
|
|
if( this._active ) {
|
|
return this._paused ? "paused" : "playing";
|
|
} else {
|
|
return "stopped";
|
|
}
|
|
},
|
|
|
|
// "private" methods
|
|
_cycle: function() {
|
|
clearTimeout(this._timer);
|
|
if(this._active){
|
|
var curr = new Date().valueOf();
|
|
var step = (curr - this._startTime) / (this._endTime - this._startTime);
|
|
|
|
if(step >= 1){
|
|
step = 1;
|
|
this._percent = 100;
|
|
}else{
|
|
this._percent = step * 100;
|
|
}
|
|
|
|
// Perform easing
|
|
if((this.easing)&&(dojo.lang.isFunction(this.easing))){
|
|
step = this.easing(step);
|
|
}
|
|
|
|
var value = this.curve.getValue(step);
|
|
this.fire("handler", ["animate", value]);
|
|
this.fire("onAnimate", [value]);
|
|
|
|
if( step < 1 ) {
|
|
this._timer = setTimeout(dojo.lang.hitch(this, "_cycle"), this.rate);
|
|
} else {
|
|
this._active = false;
|
|
this.fire("handler", ["end"]);
|
|
this.fire("onEnd");
|
|
|
|
if( this.repeatCount > 0 ) {
|
|
this.repeatCount--;
|
|
this.play(null, true);
|
|
} else if( this.repeatCount == -1 ) {
|
|
this.play(null, true);
|
|
} else {
|
|
if(this._startRepeatCount) {
|
|
this.repeatCount = this._startRepeatCount;
|
|
this._startRepeatCount = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
|
|
dojo.lfx.Combine = function(){
|
|
dojo.lfx.IAnimation.call(this);
|
|
this._anims = [];
|
|
this._animsEnded = 0;
|
|
|
|
var anims = arguments;
|
|
if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
|
|
anims = anims[0];
|
|
}
|
|
|
|
var _this = this;
|
|
dojo.lang.forEach(anims, function(anim){
|
|
_this._anims.push(anim);
|
|
var oldOnEnd = (anim["onEnd"]) ? dojo.lang.hitch(anim, "onEnd") : function(){};
|
|
anim.onEnd = function(){ oldOnEnd(); _this._onAnimsEnded(); };
|
|
});
|
|
}
|
|
dojo.inherits(dojo.lfx.Combine, dojo.lfx.IAnimation);
|
|
dojo.lang.extend(dojo.lfx.Combine, {
|
|
// private members
|
|
_animsEnded: 0,
|
|
|
|
// public methods
|
|
play: function(delay, gotoStart){
|
|
if( !this._anims.length ){ return this; }
|
|
|
|
this.fire("beforeBegin");
|
|
|
|
if(delay > 0){
|
|
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
|
|
return this;
|
|
}
|
|
|
|
if(gotoStart || this._anims[0].percent == 0){
|
|
this.fire("onBegin");
|
|
}
|
|
this.fire("onPlay");
|
|
this._animsCall("play", null, gotoStart);
|
|
return this;
|
|
},
|
|
|
|
pause: function(){
|
|
this.fire("onPause");
|
|
this._animsCall("pause");
|
|
return this;
|
|
},
|
|
|
|
stop: function(gotoEnd){
|
|
this.fire("onStop");
|
|
this._animsCall("stop", gotoEnd);
|
|
return this;
|
|
},
|
|
|
|
// private methods
|
|
_onAnimsEnded: function(){
|
|
this._animsEnded++;
|
|
if(this._animsEnded >= this._anims.length){
|
|
this.fire("onEnd");
|
|
}
|
|
return this;
|
|
},
|
|
|
|
_animsCall: function(funcName){
|
|
var args = [];
|
|
if(arguments.length > 1){
|
|
for(var i = 1 ; i < arguments.length ; i++){
|
|
args.push(arguments[i]);
|
|
}
|
|
}
|
|
var _this = this;
|
|
dojo.lang.forEach(this._anims, function(anim){
|
|
anim[funcName](args);
|
|
}, _this);
|
|
return this;
|
|
}
|
|
});
|
|
|
|
dojo.lfx.Chain = function() {
|
|
dojo.lfx.IAnimation.call(this);
|
|
this._anims = [];
|
|
this._currAnim = -1;
|
|
|
|
var anims = arguments;
|
|
if(anims.length == 1 && (dojo.lang.isArray(anims[0]) || dojo.lang.isArrayLike(anims[0]))){
|
|
anims = anims[0];
|
|
}
|
|
|
|
var _this = this;
|
|
dojo.lang.forEach(anims, function(anim, i, anims_arr){
|
|
_this._anims.push(anim);
|
|
var oldOnEnd = (anim["onEnd"]) ? dojo.lang.hitch(anim, "onEnd") : function(){};
|
|
if(i < anims_arr.length - 1){
|
|
anim.onEnd = function(){ oldOnEnd(); _this._playNext(); };
|
|
}else{
|
|
anim.onEnd = function(){ oldOnEnd(); _this.fire("onEnd"); };
|
|
}
|
|
}, _this);
|
|
}
|
|
dojo.inherits(dojo.lfx.Chain, dojo.lfx.IAnimation);
|
|
dojo.lang.extend(dojo.lfx.Chain, {
|
|
// private members
|
|
_currAnim: -1,
|
|
|
|
// public methods
|
|
play: function(delay, gotoStart){
|
|
if( !this._anims.length ) { return this; }
|
|
if( gotoStart || !this._anims[this._currAnim] ) {
|
|
this._currAnim = 0;
|
|
}
|
|
|
|
var currentAnimation = this._anims[this._currAnim];
|
|
|
|
this.fire("beforeBegin");
|
|
if(delay > 0){
|
|
setTimeout(dojo.lang.hitch(this, function(){ this.play(null, gotoStart); }), delay);
|
|
return this;
|
|
}
|
|
|
|
if(currentAnimation){
|
|
if(this._currAnim == 0){
|
|
this.fire("handler", ["begin", this._currAnim]);
|
|
this.fire("onBegin", [this._currAnim]);
|
|
}
|
|
this.fire("onPlay", [this._currAnim]);
|
|
currentAnimation.play(null, gotoStart);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
pause: function(){
|
|
if( this._anims[this._currAnim] ) {
|
|
this._anims[this._currAnim].pause();
|
|
this.fire("onPause", [this._currAnim]);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
playPause: function(){
|
|
if(this._anims.length == 0){ return this; }
|
|
if(this._currAnim == -1){ this._currAnim = 0; }
|
|
var currAnim = this._anims[this._currAnim];
|
|
if( currAnim ) {
|
|
if( !currAnim._active || currAnim._paused ) {
|
|
this.play();
|
|
} else {
|
|
this.pause();
|
|
}
|
|
}
|
|
return this;
|
|
},
|
|
|
|
stop: function(){
|
|
var currAnim = this._anims[this._currAnim];
|
|
if(currAnim){
|
|
currAnim.stop();
|
|
this.fire("onStop", [this._currAnim]);
|
|
}
|
|
return currAnim;
|
|
},
|
|
|
|
// private methods
|
|
_playNext: function(){
|
|
if( this._currAnim == -1 || this._anims.length == 0 ) { return this; }
|
|
this._currAnim++;
|
|
if( this._anims[this._currAnim] ){
|
|
this._anims[this._currAnim].play(null, true);
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
|
|
dojo.lfx.combine = function(){
|
|
var anims = arguments;
|
|
if(dojo.lang.isArray(arguments[0])){
|
|
anims = arguments[0];
|
|
}
|
|
return new dojo.lfx.Combine(anims);
|
|
}
|
|
|
|
dojo.lfx.chain = function(){
|
|
var anims = arguments;
|
|
if(dojo.lang.isArray(arguments[0])){
|
|
anims = arguments[0];
|
|
}
|
|
return new dojo.lfx.Chain(anims);
|
|
}
|