http://developer.yahoo.net/yui/license.txtYAHOO.util.Anim = function(el, attributes, duration, method) {
if (el) {
this.init(el, attributes, duration, method);
}
};
YAHOO.util.Anim.prototype = {
toString: function() {
var el = this.getEl();
var id = el.id || el.tagName;
return ("Anim " + id);
},
patterns: { noNegatives: /width|height|opacity|padding/i, offsetAttribute: /^((width|height)|(top|left))$/, defaultUnit: /width|height|top$|bottom$|left$|right$/i, offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i },
doMethod: function(attr, start, end) {
return this.method(this.currentFrame, start, end - start, this.totalFrames);
},
setAttribute: function(attr, val, unit) {
if ( this.patterns.noNegatives.test(attr) ) {
val = (val > 0) ? val : 0;
}
YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit);
},
getAttribute: function(attr) {
var el = this.getEl();
var val = YAHOO.util.Dom.getStyle(el, attr);
if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
return parseFloat(val);
}
var a = this.patterns.offsetAttribute.exec(attr) || [];
var pos = !!( a[3] ); var box = !!( a[2] ); if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
} else { val = 0;
}
return val;
},
getDefaultUnit: function(attr) {
if ( this.patterns.defaultUnit.test(attr) ) {
return 'px';
}
return '';
},
setRuntimeAttribute: function(attr) {
var start;
var end;
var attributes = this.attributes;
this.runtimeAttributes[attr] = {};
var isset = function(prop) {
return (typeof prop !== 'undefined');
};
if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
return false; }
start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
if ( isset(attributes[attr]['to']) ) {
end = attributes[attr]['to'];
} else if ( isset(attributes[attr]['by']) ) {
if (start.constructor == Array) {
end = [];
for (var i = 0, len = start.length; i < len; ++i) {
end[i] = start[i] + attributes[attr]['by'][i];
}
} else {
end = start + attributes[attr]['by'];
}
}
this.runtimeAttributes[attr].start = start;
this.runtimeAttributes[attr].end = end;
this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
},
init: function(el, attributes, duration, method) {
var isAnimated = false;
var startTime = null;
var actualFrames = 0;
el = YAHOO.util.Dom.get(el);
this.attributes = attributes || {};
this.duration = duration || 1;
this.method = method || YAHOO.util.Easing.easeNone;
this.useSeconds = true; this.currentFrame = 0;
this.totalFrames = YAHOO.util.AnimMgr.fps;
this.getEl = function() { return el; };
this.isAnimated = function() {
return isAnimated;
};
this.getStartTime = function() {
return startTime;
};
this.runtimeAttributes = {};
this.animate = function() {
if ( this.isAnimated() ) { return false; }
this.currentFrame = 0;
this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration;
YAHOO.util.AnimMgr.registerElement(this);
};
this.stop = function(finish) {
if (finish) {
this.currentFrame = this.totalFrames;
this._onTween.fire();
}
YAHOO.util.AnimMgr.stop(this);
};
var onStart = function() {
this.onStart.fire();
this.runtimeAttributes = {};
for (var attr in this.attributes) {
this.setRuntimeAttribute(attr);
}
isAnimated = true;
actualFrames = 0;
startTime = new Date();
};
var onTween = function() {
var data = {
duration: new Date() - this.getStartTime(),
currentFrame: this.currentFrame
};
data.toString = function() {
return (
'duration: ' + data.duration +
', currentFrame: ' + data.currentFrame
);
};
this.onTween.fire(data);
var runtimeAttributes = this.runtimeAttributes;
for (var attr in runtimeAttributes) {
this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
}
actualFrames += 1;
};
var onComplete = function() {
var actual_duration = (new Date() - startTime) / 1000 ;
var data = {
duration: actual_duration,
frames: actualFrames,
fps: actualFrames / actual_duration
};
data.toString = function() {
return (
'duration: ' + data.duration +
', frames: ' + data.frames +
', fps: ' + data.fps
);
};
isAnimated = false;
actualFrames = 0;
this.onComplete.fire(data);
};
this._onStart = new YAHOO.util.CustomEvent('_start', this, true);
this.onStart = new YAHOO.util.CustomEvent('start', this);
this.onTween = new YAHOO.util.CustomEvent('tween', this);
this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
this.onComplete = new YAHOO.util.CustomEvent('complete', this);
this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true);
this._onStart.subscribe(onStart);
this._onTween.subscribe(onTween);
this._onComplete.subscribe(onComplete);
}
};
YAHOO.util.AnimMgr = new function() {
var thread = null;
var queue = [];
var tweenCount = 0;
this.fps = 200;
this.delay = 1;
this.registerElement = function(tween) {
queue[queue.length] = tween;
tweenCount += 1;
tween._onStart.fire();
this.start();
};
this.unRegister = function(tween, index) {
tween._onComplete.fire();
index = index || getIndex(tween);
if (index != -1) { queue.splice(index, 1); }
tweenCount -= 1;
if (tweenCount <= 0) { this.stop(); }
};
this.start = function() {
if (thread === null) { thread = setInterval(this.run, this.delay); }
};
this.stop = function(tween) {
if (!tween) {
clearInterval(thread);
for (var i = 0, len = queue.length; i < len; ++i) {
if (queue[i].isAnimated()) {
this.unRegister(tween, i);
}
}
queue = [];
thread = null;
tweenCount = 0;
}
else {
this.unRegister(tween);
}
};
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; }
}
return -1;
};
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 { tweak = frames - (frame + 1);
}
if (tweak > 0 && isFinite(tweak)) { if (tween.currentFrame + tweak >= frames) {tweak = frames - (frame + 1);
}
tween.currentFrame += tweak;
}
};
};
YAHOO.util.Bezier = new function()
{
this.getPosition = function(points, t)
{
var n = points.length;
var tmp = [];
for (var i = 0; i < n; ++i){
tmp[i] = [points[i][0], points[i][1]]; }
for (var j = 1; j < n; ++j) {
for (i = 0; i < n - j; ++i) {
tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
}
}
return [ tmp[0][0], tmp[0][1] ];
};
};
(function() {
YAHOO.util.ColorAnim = function(el, attributes, duration, method) {
YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
};
YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim);
var Y = YAHOO.util;
var superclass = Y.ColorAnim.superclass;
var proto = Y.ColorAnim.prototype;
proto.toString = function() {
var el = this.getEl();
var id = el.id || el.tagName;
return ("ColorAnim " + id);
};
proto.patterns.color = /color$/i;
proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; proto.parseColor = function(s) {
if (s.length == 3) { return s; }
var c = this.patterns.hex.exec(s);
if (c && c.length == 4) {
return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
}
c = this.patterns.rgb.exec(s);
if (c && c.length == 4) {
return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
}
c = this.patterns.hex3.exec(s);
if (c && c.length == 4) {
return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
}
return null;
};
proto.getAttribute = function(attr) {
var el = this.getEl();
if ( this.patterns.color.test(attr) ) {
var val = YAHOO.util.Dom.getStyle(el, attr);
if (this.patterns.transparent.test(val)) { var parent = el.parentNode; val = Y.Dom.getStyle(parent, attr);
while (parent && this.patterns.transparent.test(val)) {
parent = parent.parentNode;
val = Y.Dom.getStyle(parent, attr);
if (parent.tagName.toUpperCase() == 'HTML') {
val = '#fff';
}
}
}
} else {
val = superclass.getAttribute.call(this, attr);
}
return val;
};
proto.doMethod = function(attr, start, end) {
var val;
if ( this.patterns.color.test(attr) ) {
val = [];
for (var i = 0, len = start.length; i < len; ++i) {
val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
}
val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
}
else {
val = superclass.doMethod.call(this, attr, start, end);
}
return val;
};
proto.setRuntimeAttribute = function(attr) {
superclass.setRuntimeAttribute.call(this, attr);
if ( this.patterns.color.test(attr) ) {
var attributes = this.attributes;
var start = this.parseColor(this.runtimeAttributes[attr].start);
var end = this.parseColor(this.runtimeAttributes[attr].end);
if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
end = this.parseColor(attributes[attr].by);
for (var i = 0, len = start.length; i < len; ++i) {
end[i] = start[i] + end[i];
}
}
this.runtimeAttributes[attr].start = start;
this.runtimeAttributes[attr].end = end;
}
};
})();YAHOO.util.Easing = {
easeNone: function (t, b, c, d) {
return c*t/d + b;
},
/**
* Begins slowly and accelerates towards end. (quadratic)
* @method easeIn
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @return {Number} The computed value for the current animation frame
*/
easeIn: function (t, b, c, d) {
return c*(t/=d)*t + b;
},
easeOut: function (t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
},
/**
* Begins slowly and decelerates towards end. (quadratic)
* @method easeBoth
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @return {Number} The computed value for the current animation frame
*/
easeBoth: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
/**
* Begins slowly and accelerates towards end. (quartic)
* @method easeInStrong
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @return {Number} The computed value for the current animation frame
*/
easeInStrong: function (t, b, c, d) {
return c*(t/=d)*t*t*t + b;
},
easeOutStrong: function (t, b, c, d) {
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
/**
* Begins slowly and decelerates towards end. (quartic)
* @method easeBothStrong
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @return {Number} The computed value for the current animation frame
*/
easeBothStrong: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
/**
* Snap in elastic effect.
* @method elasticIn
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @param {Number} p Period (optional)
* @return {Number} The computed value for the current animation frame
*/
elasticIn: function (t, b, c, d, a, p) {
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
elasticOut: function (t, b, c, d, a, p) {
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
/**
* Snap both elastic effect.
* @method elasticBoth
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @param {Number} p Period (optional)
* @return {Number} The computed value for the current animation frame
*/
elasticBoth: function (t, b, c, d, a, p) {
if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
},
backIn: function (t, b, c, d, s) {
if (typeof s == 'undefined') s = 1.70158;
return c*(t/=d)*t*((s+1)*t - s) + b;
},
/**
* Overshoots end, then reverses and comes back to end.
* @method backOut
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @param {Number} s Overshoot (optional)
* @return {Number} The computed value for the current animation frame
*/
backOut: function (t, b, c, d, s) {
if (typeof s == 'undefined') s = 1.70158;
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
backBoth: function (t, b, c, d, s) {
if (typeof s == 'undefined') s = 1.70158;
if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
bounceIn: function (t, b, c, d) {
return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
},
bounceOut: function (t, b, c, d) {
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
}
},
/**
* Bounces off start and end.
* @method bounceBoth
* @param {Number} t Time value used to compute current value
* @param {Number} b Starting value
* @param {Number} c Delta between start and end values
* @param {Number} d Total length of animation
* @return {Number} The computed value for the current animation frame
*/
bounceBoth: function (t, b, c, d) {
if (t < d/2) return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
}
};
(function() {
YAHOO.util.Motion = function(el, attributes, duration, method) {
if (el) { YAHOO.util.Motion.superclass.constructor.call(this, el, attributes, duration, method);
}
};
YAHOO.extend(YAHOO.util.Motion, YAHOO.util.ColorAnim);
var Y = YAHOO.util;
var superclass = Y.Motion.superclass;
var proto = Y.Motion.prototype;
proto.toString = function() {
var el = this.getEl();
var id = el.id || el.tagName;
return ("Motion " + id);
};
proto.patterns.points = /^points$/i;
proto.setAttribute = function(attr, val, unit) {
if ( this.patterns.points.test(attr) ) {
unit = unit || 'px';
superclass.setAttribute.call(this, 'left', val[0], unit);
superclass.setAttribute.call(this, 'top', val[1], unit);
} else {
superclass.setAttribute.call(this, attr, val, unit);
}
};
proto.getAttribute = function(attr) {
if ( this.patterns.points.test(attr) ) {
var val = [
superclass.getAttribute.call(this, 'left'),
superclass.getAttribute.call(this, 'top')
];
} else {
val = superclass.getAttribute.call(this, attr);
}
return val;
};
proto.doMethod = function(attr, start, end) {
var val = null;
if ( this.patterns.points.test(attr) ) {
var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
} else {
val = superclass.doMethod.call(this, attr, start, end);
}
return val;
};
proto.setRuntimeAttribute = function(attr) {
if ( this.patterns.points.test(attr) ) {
var el = this.getEl();
var attributes = this.attributes;
var start;
var control = attributes['points']['control'] || [];
var end;
var i, len;
if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
control = [control];
} else { // break reference to attributes.points.control
var tmp = [];
for (i = 0, len = control.length; i< len; ++i) {
tmp[i] = control[i];
}
control = tmp;
}
if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
Y.Dom.setStyle(el, 'position', 'relative');
}
if ( isset(attributes['points']['from']) ) {
Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
}
else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
start = this.getAttribute('points'); // get actual top & left
// TO beats BY, per SMIL 2.1 spec
if ( isset(attributes['points']['to']) ) {
end = translateValues.call(this, attributes['points']['to'], start);
var pageXY = Y.Dom.getXY(this.getEl());
for (i = 0, len = control.length; i < len; ++i) {
control[i] = translateValues.call(this, control[i], start);
}
} else if ( isset(attributes['points']['by']) ) {
end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
for (i = 0, len = control.length; i < len; ++i) {
control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
}
}
this.runtimeAttributes[attr] = [start];
if (control.length > 0) {
this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
}
this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
}
else {
superclass.setRuntimeAttribute.call(this, attr);
}
};
var translateValues = function(val, start) {
var pageXY = Y.Dom.getXY(this.getEl());
val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
return val;
};
var isset = function(prop) {
return (typeof prop !== 'undefined');
};
})();
/**
* Anim subclass for scrolling elements to a position defined by the "scroll"
* member of "attributes". All "scroll" members are arrays with x, y scroll positions.
* <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
* @class Scroll
* @namespace YAHOO.util
* @requires YAHOO.util.Anim
* @requires YAHOO.util.AnimMgr
* @requires YAHOO.util.Easing
* @requires YAHOO.util.Bezier
* @requires YAHOO.util.Dom
* @requires YAHOO.util.Event
* @requires YAHOO.util.CustomEvent
* @extends YAHOO.util.Anim
* @constructor
* @param {String or HTMLElement} el Reference to the element that will be animated
* @param {Object} attributes The attribute(s) to be animated.
* Each attribute is an object with at minimum a "to" or "by" member defined.
* Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
* All attribute names use camelCase.
* @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
* @param {Function} method (optional, defaults to YAHOO.util.Easing.easeNone) Computes the values that are applied to the attributes per frame (generally a YAHOO.util.Easing method)
*/
(function() {
YAHOO.util.Scroll = function(el, attributes, duration, method) {
if (el) { // dont break existing subclasses not using YAHOO.extend
YAHOO.util.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
}
};
YAHOO.extend(YAHOO.util.Scroll, YAHOO.util.ColorAnim);
// shorthand
var Y = YAHOO.util;
var superclass = Y.Scroll.superclass;
var proto = Y.Scroll.prototype;
proto.toString = function() {
var el = this.getEl();
var id = el.id || el.tagName;
return ("Scroll " + id);
};
proto.doMethod = function(attr, start, end) {
var val = null;
if (attr == 'scroll') {
val = [
this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
];
} else {
val = superclass.doMethod.call(this, attr, start, end);
}
return val;
};
proto.getAttribute = function(attr) {
var val = null;
var el = this.getEl();
if (attr == 'scroll') {
val = [ el.scrollLeft, el.scrollTop ];
} else {
val = superclass.getAttribute.call(this, attr);
}
return val;
};
proto.setAttribute = function(attr, val, unit) {
var el = this.getEl();
if (attr == 'scroll') {
el.scrollLeft = val[0];
el.scrollTop = val[1];
} else {
superclass.setAttribute.call(this, attr, val, unit);
}
};
})();