/**
* Handles animation queueing and threading.
* Used by Anim and subclasses.
* @class AnimMgr
* @namespace YAHOO.util
*/
YAHOO.util.AnimMgr = new function() {
/**
* Reference to the animation Interval.
* @property thread
* @private
* @type Int
*/
var thread = null;
/**
* The current queue of registered animation objects.
* @property queue
* @private
* @type Array
*/
var queue = [];
/**
* The number of active animations.
* @property tweenCount
* @private
* @type Int
*/
var tweenCount = 0;
/**
* Base frame rate (frames per second).
* Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
* @property fps
* @type Int
*
*/
this.fps = 1000;
/**
* Interval delay in milliseconds, defaults to fastest possible.
* @property delay
* @type Int
*
*/
this.delay = 20;
/**
* Adds an animation instance to the animation queue.
* All animation instances must be registered in order to animate.
* @method registerElement
* @param {object} tween The Anim instance to be be registered
*/
this.registerElement = function(tween) {
queue[queue.length] = tween;
tweenCount += 1;
tween._onStart.fire();
this.start();
};
var _unregisterQueue = [];
var _unregistering = false;
var doUnregister = function() {
var next_args = _unregisterQueue.shift();
unRegister.apply(YAHOO.util.AnimMgr,next_args);
if (_unregisterQueue.length) {
arguments.callee();
}
};
var unRegister = function(tween, index) {
index = index || getIndex(tween);
if (!tween.isAnimated() || index === -1) {
return false;
}
tween._onComplete.fire();
queue.splice(index, 1);
tweenCount -= 1;
if (tweenCount <= 0) {
this.stop();
}
return true;
};
/**
* removes an animation instance from the animation queue.
* All animation instances must be registered in order to animate.
* @method unRegister
* @param {object} tween The Anim instance to be be registered
* @param {Int} index The index of the Anim instance
* @private
*/
this.unRegister = function() {
_unregisterQueue.push(arguments);
if (!_unregistering) {
_unregistering = true;
doUnregister();
_unregistering = false;
}
}
/**
* Starts the animation thread.
* Only one thread can run at a time.
* @method start
*/
this.start = function() {
if (thread === null) {
thread = setInterval(this.run, this.delay);
}
};
/**
* Stops the animation thread or a specific animation instance.
* @method stop
* @param {object} tween A specific Anim instance to stop (optional)
* If no instance given, Manager stops thread and all animations.
*/
this.stop = function(tween) {
if (!tween) {
clearInterval(thread);
for (var i = 0, len = queue.length; i < len; ++i) {
this.unRegister(queue[0], 0);
}
queue = [];
thread = null;
tweenCount = 0;
}
else {
this.unRegister(tween);
}
};
/**
* Called per Interval to handle each animation frame.
* @method run
*/
this.run = function() {
for (var i = 0, len = queue.length; i < len; ++i) {
var tween = queue[i];
if ( !tween || !tween.isAnimated() ) { continue; }
if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
{
tween.currentFrame += 1;
if (tween.useSeconds) {
correctFrame(tween);
}
tween._onTween.fire();
}
else { YAHOO.util.AnimMgr.stop(tween, i); }
}
};
var getIndex = function(anim) {
for (var i = 0, len = queue.length; i < len; ++i) {
if (queue[i] === anim) {
return i; // note return;
}
}
return -1;
};
/**
* On the fly frame correction to keep animation on time.
* @method correctFrame
* @private
* @param {Object} tween The Anim instance being corrected.
*/
var correctFrame = function(tween) {
var frames = tween.totalFrames;
var frame = tween.currentFrame;
var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
var elapsed = (new Date() - tween.getStartTime());
var tweak = 0;
if (elapsed < tween.duration * 1000) { // check if falling behind
tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
} else { // went over duration, so jump to end
tweak = frames - (frame + 1);
}
if (tweak > 0 && isFinite(tweak)) { // adjust if needed
if (tween.currentFrame + tweak >= frames) {// dont go past last frame
tweak = frames - (frame + 1);
}
tween.currentFrame += tweak;
}
};
this._queue = queue;
this._getIndex = getIndex;
};