📄 animation.js
字号:
/**
* Custom event that fires after onTween
* @private
*/
this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
/**
* Custom event that fires when animation ends
* Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
*/
this.onComplete = new YAHOO.util.CustomEvent('complete', this);
/**
* Custom event that fires after onComplete
* @private
*/
this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true);
this._onStart.subscribe(onStart);
this._onTween.subscribe(onTween);
this._onComplete.subscribe(onComplete);
}
};
/**
* @class Handles animation queueing and threading.
* Used by Anim and subclasses.
*/
YAHOO.util.AnimMgr = new function() {
/**
* Reference to the animation Interval
* @private
* @type Int
*/
var thread = null;
/**
* The current queue of registered animation objects.
* @private
* @type Array
*/
var queue = [];
/**
* The number of active animations.
* @private
* @type Int
*/
var tweenCount = 0;
/**
* Base frame rate (frames per second).
* Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
* @type Int
*
*/
this.fps = 200;
/**
* Interval delay in milliseconds, defaults to fastest possible.
* @type Int
*
*/
this.delay = 1;
/**
* Adds an animation instance to the animation queue.
* All animation instances must be registered in order to animate.
* @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();
};
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(); }
};
/**
* Starts the animation thread.
* Only one thread can run at a time.
*/
this.start = function() {
if (thread === null) { thread = setInterval(this.run, this.delay); }
};
/**
* Stops the animation thread or a specific animation instance.
* @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) {
if (queue[i].isAnimated()) {
this.unRegister(tween, i);
}
}
queue = [];
thread = null;
tweenCount = 0;
}
else {
this.unRegister(tween);
}
};
/**
* Called per Interval to handle each animation frame.
*/
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.
* @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;
}
};
};
/**
*
* @class Used to calculate Bezier splines for any number of control points.
*
*/
YAHOO.util.Bezier = new function()
{
/**
* Get the current position of the animated element based on t.
* Each point is an array of "x" and "y" values (0 = x, 1 = y)
* At least 2 points are required (start and end).
* First point is start. Last point is end.
* Additional control points are optional.
* @param {Array} points An array containing Bezier points
* @param {Number} t A number between 0 and 1 which is the basis for determining current position
* @return {Array} An array containing int x and y member data
*/
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]]; // save input
}
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] ];
};
};
/**
* @class ColorAnim subclass for color fading
* <p>Usage: <code>var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);</code></p>
* <p>Color values can be specified with either 112233, #112233, [255,255,255], or rgb(255,255,255)
* @requires YAHOO.util.Anim
* @requires YAHOO.util.AnimMgr
* @requires YAHOO.util.Easing
* @requires YAHOO.util.Bezier
* @requires YAHOO.util.Dom
* @requires YAHOO.util.Event
* @constructor
* @param {HTMLElement | String} 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.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);
// shorthand
var Y = YAHOO.util;
var superclass = Y.ColorAnim.superclass;
var proto = Y.ColorAnim.prototype;
/**
* toString method
* @return {String} string represenation of anim obj
*/
proto.toString = function() {
var el = this.getEl();
var id = el.id || el.tagName;
return ("ColorAnim " + id);
};
/**
* Only certain attributes should be treated as colors.
* @type Object
*/
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;
/**
* Attempts to parse the given string and return a 3-tuple.
* @param {String} s The string to parse.
* @return {Array} The 3-tuple of rgb values.
*/
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;
};
/**
* Returns current value of the attribute.
* @param {String} attr The name of the attribute.
* @return {Number} val The current value of the attribute.
*/
proto.getAttribute = function(attr) {
var el = this.getEl();
if ( this.patterns.color.test(attr) ) {
var val = YAHOO.util.Dom.getStyle(el, attr);
if (val == 'transparent') { // bgcolor default
var parent = el.parentNode; // try and get from an ancestor
val = Y.Dom.getStyle(parent, attr);
while (parent && val == 'transparent') {
parent = parent.parentNode;
val = Y.Dom.getStyle(parent, attr);
if (parent.tagName.toUpperCase() == 'HTML') {
val = 'ffffff';
}
}
}
} else {
val = superclass.getAttribute.call(this, attr);
}
return val;
};
/**
* Returns the value computed by the animation's "method".
* @param {String} attr The name of the attribute.
* @param {Number} start The value this attribute should start from for this animation.
* @param {Number} end The value this attribute should end at for this animation.
* @return {Number} The Value to be applied to the attribute.
*/
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;
};
/**
* Sets the actual values to be used during the animation.
* Should only be needed for subclass use.
* @param {Object} attr The attribute object
* @private
*/
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);
// fix colors if going "by"
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;
}
};
})();/*
TERMS OF USE - EASING EQUATIONS
Open source under the BSD License.
Copyright
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -