2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
12 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
13 Code licensed under the BSD License:
14 http://developer.yahoo.net/yui/license.txt
18 * The animation module provides allows effects to be added to HTMLElements.
20 * @requires yahoo, event, dom
25 * Base animation class that provides the interface for building animated effects.
26 * <p>Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);</p>
28 * @namespace YAHOO.util
29 * @requires YAHOO.util.AnimMgr
30 * @requires YAHOO.util.Easing
31 * @requires YAHOO.util.Dom
32 * @requires YAHOO.util.Event
33 * @requires YAHOO.util.CustomEvent
35 * @param {String | HTMLElement} el Reference to the element that will be animated
36 * @param {Object} attributes The attribute(s) to be animated.
37 * Each attribute is an object with at minimum a "to" or "by" member defined.
38 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
39 * All attribute names use camelCase.
40 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
41 * @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)
44 var Anim = function(el, attributes, duration, method) {
47 this.init(el, attributes, duration, method);
54 * Provides a readable name for the Anim instance.
58 toString: function() {
59 var el = this.getEl() || {};
60 var id = el.id || el.tagName;
61 return (this.constructor.NAME + ': ' + id);
64 patterns: { // cached for performance
65 noNegatives: /width|height|opacity|padding/i, // keep at zero or above
66 offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default
67 defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default
68 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset
72 * Returns the value computed by the animation's "method".
74 * @param {String} attr The name of the attribute.
75 * @param {Number} start The value this attribute should start from for this animation.
76 * @param {Number} end The value this attribute should end at for this animation.
77 * @return {Number} The Value to be applied to the attribute.
79 doMethod: function(attr, start, end) {
80 return this.method(this.currentFrame, start, end - start, this.totalFrames);
84 * Applies a value to an attribute.
85 * @method setAttribute
86 * @param {String} attr The name of the attribute.
87 * @param {Number} val The value to be applied to the attribute.
88 * @param {String} unit The unit ('px', '%', etc.) of the value.
90 setAttribute: function(attr, val, unit) {
91 var el = this.getEl();
92 if ( this.patterns.noNegatives.test(attr) ) {
93 val = (val > 0) ? val : 0;
96 if (attr in el && !('style' in el && attr in el.style)) {
99 Y.Dom.setStyle(el, attr, val + unit);
104 * Returns current value of the attribute.
105 * @method getAttribute
106 * @param {String} attr The name of the attribute.
107 * @return {Number} val The current value of the attribute.
109 getAttribute: function(attr) {
110 var el = this.getEl();
111 var val = Y.Dom.getStyle(el, attr);
113 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
114 return parseFloat(val);
117 var a = this.patterns.offsetAttribute.exec(attr) || [];
118 var pos = !!( a[3] ); // top or left
119 var box = !!( a[2] ); // width or height
122 // use offsets for width/height and abs pos top/left
123 if ( box || (Y.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
124 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
125 } else { // default to zero for other 'auto'
128 } else if (attr in el) {
136 * Returns the unit to use when none is supplied.
137 * @method getDefaultUnit
138 * @param {attr} attr The name of the attribute.
139 * @return {String} The default unit to be used.
141 getDefaultUnit: function(attr) {
142 if ( this.patterns.defaultUnit.test(attr) ) {
150 * Sets the actual values to be used during the animation. Should only be needed for subclass use.
151 * @method setRuntimeAttribute
152 * @param {Object} attr The attribute object
155 setRuntimeAttribute: function(attr) {
158 var attributes = this.attributes;
160 this.runtimeAttributes[attr] = {};
162 var isset = function(prop) {
163 return (typeof prop !== 'undefined');
166 if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
167 return false; // note return; nothing to animate to
170 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
172 // To beats by, per SMIL 2.1 spec
173 if ( isset(attributes[attr]['to']) ) {
174 end = attributes[attr]['to'];
175 } else if ( isset(attributes[attr]['by']) ) {
176 if (start.constructor == Array) {
178 for (var i = 0, len = start.length; i < len; ++i) {
179 end[i] = start[i] + attributes[attr]['by'][i] * 1; // times 1 to cast "by"
182 end = start + attributes[attr]['by'] * 1;
186 this.runtimeAttributes[attr].start = start;
187 this.runtimeAttributes[attr].end = end;
189 // set units if needed
190 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ?
191 attributes[attr]['unit'] : this.getDefaultUnit(attr);
196 * Constructor for Anim instance.
198 * @param {String | HTMLElement} el Reference to the element that will be animated
199 * @param {Object} attributes The attribute(s) to be animated.
200 * Each attribute is an object with at minimum a "to" or "by" member defined.
201 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
202 * All attribute names use camelCase.
203 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
204 * @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)
206 init: function(el, attributes, duration, method) {
208 * Whether or not the animation is running.
209 * @property isAnimated
213 var isAnimated = false;
216 * A Date object that is created when the animation begins.
217 * @property startTime
221 var startTime = null;
224 * The number of frames this animation was able to execute.
225 * @property actualFrames
229 var actualFrames = 0;
232 * The element to be animated.
240 * The collection of attributes to be animated.
241 * Each attribute must have at least a "to" or "by" defined in order to animate.
242 * If "to" is supplied, the animation will end with the attribute at that value.
243 * If "by" is supplied, the animation will end at that value plus its starting value.
244 * If both are supplied, "to" is used, and "by" is ignored.
245 * Optional additional member include "from" (the value the attribute should start animating from, defaults to current value), and "unit" (the units to apply to the values).
246 * @property attributes
249 this.attributes = attributes || {};
252 * The length of the animation. Defaults to "1" (second).
256 this.duration = !YAHOO.lang.isUndefined(duration) ? duration : 1;
259 * The method that will provide values to the attribute(s) during the animation.
260 * Defaults to "YAHOO.util.Easing.easeNone".
264 this.method = method || Y.Easing.easeNone;
267 * Whether or not the duration should be treated as seconds.
269 * @property useSeconds
272 this.useSeconds = true; // default to seconds
275 * The location of the current animation on the timeline.
276 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
277 * @property currentFrame
280 this.currentFrame = 0;
283 * The total number of frames to be executed.
284 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
285 * @property totalFrames
288 this.totalFrames = Y.AnimMgr.fps;
291 * Changes the animated element
294 this.setEl = function(element) {
295 el = Y.Dom.get(element);
299 * Returns a reference to the animated element.
301 * @return {HTMLElement}
303 this.getEl = function() { return el; };
306 * Checks whether the element is currently animated.
308 * @return {Boolean} current value of isAnimated.
310 this.isAnimated = function() {
315 * Returns the animation start time.
316 * @method getStartTime
317 * @return {Date} current value of startTime.
319 this.getStartTime = function() {
323 this.runtimeAttributes = {};
328 * Starts the animation by registering it with the animation manager.
331 this.animate = function() {
332 if ( this.isAnimated() ) {
336 this.currentFrame = 0;
338 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Y.AnimMgr.fps * this.duration) : this.duration;
340 if (this.duration === 0 && this.useSeconds) { // jump to last frame if zero second duration
341 this.totalFrames = 1;
343 Y.AnimMgr.registerElement(this);
348 * Stops the animation. Normally called by AnimMgr when animation completes.
350 * @param {Boolean} finish (optional) If true, animation will jump to final frame.
352 this.stop = function(finish) {
353 if (!this.isAnimated()) { // nothing to stop
358 this.currentFrame = this.totalFrames;
359 this._onTween.fire();
361 Y.AnimMgr.stop(this);
364 this._handleStart = function() {
367 this.runtimeAttributes = {};
368 for (var attr in this.attributes) {
369 if (this.attributes.hasOwnProperty(attr)) {
370 this.setRuntimeAttribute(attr);
376 startTime = new Date();
380 * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s).
384 this._handleTween = function() {
386 duration: new Date() - this.getStartTime(),
387 currentFrame: this.currentFrame
390 data.toString = function() {
392 'duration: ' + data.duration +
393 ', currentFrame: ' + data.currentFrame
397 this.onTween.fire(data);
399 var runtimeAttributes = this.runtimeAttributes;
401 for (var attr in runtimeAttributes) {
402 if (runtimeAttributes.hasOwnProperty(attr)) {
403 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
407 this.afterTween.fire(data);
412 this._handleComplete = function() {
413 var actual_duration = (new Date() - startTime) / 1000 ;
416 duration: actual_duration,
417 frames: actualFrames,
418 fps: actualFrames / actual_duration
421 data.toString = function() {
423 'duration: ' + data.duration +
424 ', frames: ' + data.frames +
431 this.onComplete.fire(data);
435 * Custom event that fires after onStart, useful in subclassing
438 this._onStart = new Y.CustomEvent('_start', this, true);
441 * Custom event that fires when animation begins
442 * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction)
445 this.onStart = new Y.CustomEvent('start', this);
448 * Custom event that fires between each frame
449 * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction)
452 this.onTween = new Y.CustomEvent('tween', this);
455 * Custom event that fires between each frame
456 * Listen via subscribe method (e.g. myAnim.afterTween.subscribe(someFunction)
459 this.afterTween = new Y.CustomEvent('afterTween', this);
462 * Custom event that fires after onTween
465 this._onTween = new Y.CustomEvent('_tween', this, true);
468 * Custom event that fires when animation ends
469 * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
472 this.onComplete = new Y.CustomEvent('complete', this);
474 * Custom event that fires after onComplete
477 this._onComplete = new Y.CustomEvent('_complete', this, true);
479 this._onStart.subscribe(this._handleStart);
480 this._onTween.subscribe(this._handleTween);
481 this._onComplete.subscribe(this._handleComplete);
488 * Handles animation queueing and threading.
489 * Used by Anim and subclasses.
491 * @namespace YAHOO.util
493 YAHOO.util.AnimMgr = new function() {
495 * Reference to the animation Interval.
503 * The current queue of registered animation objects.
511 * The number of active animations.
512 * @property tweenCount
519 * Base frame rate (frames per second).
520 * Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
528 * Interval delay in milliseconds, defaults to fastest possible.
536 * Adds an animation instance to the animation queue.
537 * All animation instances must be registered in order to animate.
538 * @method registerElement
539 * @param {object} tween The Anim instance to be be registered
541 this.registerElement = function(tween) {
542 queue[queue.length] = tween;
544 tween._onStart.fire();
548 var _unregisterQueue = [];
549 var _unregistering = false;
551 var doUnregister = function() {
552 var next_args = _unregisterQueue.shift();
553 unRegister.apply(YAHOO.util.AnimMgr,next_args);
554 if (_unregisterQueue.length) {
559 var unRegister = function(tween, index) {
560 index = index || getIndex(tween);
561 if (!tween.isAnimated() || index === -1) {
565 tween._onComplete.fire();
566 queue.splice(index, 1);
569 if (tweenCount <= 0) {
577 * removes an animation instance from the animation queue.
578 * All animation instances must be registered in order to animate.
580 * @param {object} tween The Anim instance to be be registered
581 * @param {Int} index The index of the Anim instance
584 this.unRegister = function() {
585 _unregisterQueue.push(arguments);
586 if (!_unregistering) {
587 _unregistering = true;
589 _unregistering = false;
594 * Starts the animation thread.
595 * Only one thread can run at a time.
598 this.start = function() {
599 if (thread === null) {
600 thread = setInterval(this.run, this.delay);
605 * Stops the animation thread or a specific animation instance.
607 * @param {object} tween A specific Anim instance to stop (optional)
608 * If no instance given, Manager stops thread and all animations.
610 this.stop = function(tween) {
612 clearInterval(thread);
614 for (var i = 0, len = queue.length; i < len; ++i) {
615 this.unRegister(queue[0], 0);
623 this.unRegister(tween);
628 * Called per Interval to handle each animation frame.
631 this.run = function() {
632 for (var i = 0, len = queue.length; i < len; ++i) {
633 var tween = queue[i];
634 if ( !tween || !tween.isAnimated() ) { continue; }
636 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
638 tween.currentFrame += 1;
640 if (tween.useSeconds) {
643 tween._onTween.fire();
645 else { YAHOO.util.AnimMgr.stop(tween, i); }
649 var getIndex = function(anim) {
650 for (var i = 0, len = queue.length; i < len; ++i) {
651 if (queue[i] === anim) {
652 return i; // note return;
659 * On the fly frame correction to keep animation on time.
660 * @method correctFrame
662 * @param {Object} tween The Anim instance being corrected.
664 var correctFrame = function(tween) {
665 var frames = tween.totalFrames;
666 var frame = tween.currentFrame;
667 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
668 var elapsed = (new Date() - tween.getStartTime());
671 if (elapsed < tween.duration * 1000) { // check if falling behind
672 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
673 } else { // went over duration, so jump to end
674 tweak = frames - (frame + 1);
676 if (tweak > 0 && isFinite(tweak)) { // adjust if needed
677 if (tween.currentFrame + tweak >= frames) {// dont go past last frame
678 tweak = frames - (frame + 1);
681 tween.currentFrame += tweak;
685 this._getIndex = getIndex;
688 * Used to calculate Bezier splines for any number of control points.
690 * @namespace YAHOO.util
693 YAHOO.util.Bezier = new function() {
695 * Get the current position of the animated element based on t.
696 * Each point is an array of "x" and "y" values (0 = x, 1 = y)
697 * At least 2 points are required (start and end).
698 * First point is start. Last point is end.
699 * Additional control points are optional.
700 * @method getPosition
701 * @param {Array} points An array containing Bezier points
702 * @param {Number} t A number between 0 and 1 which is the basis for determining current position
703 * @return {Array} An array containing int x and y member data
705 this.getPosition = function(points, t) {
706 var n = points.length;
709 for (var i = 0; i < n; ++i){
710 tmp[i] = [points[i][0], points[i][1]]; // save input
713 for (var j = 1; j < n; ++j) {
714 for (i = 0; i < n - j; ++i) {
715 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
716 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
720 return [ tmp[0][0], tmp[0][1] ];
726 * Anim subclass for color transitions.
727 * <p>Usage: <code>var myAnim = new Y.ColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.Easing.easeOut);</code> Color values can be specified with either 112233, #112233,
728 * [255,255,255], or rgb(255,255,255)</p>
730 * @namespace YAHOO.util
731 * @requires YAHOO.util.Anim
732 * @requires YAHOO.util.AnimMgr
733 * @requires YAHOO.util.Easing
734 * @requires YAHOO.util.Bezier
735 * @requires YAHOO.util.Dom
736 * @requires YAHOO.util.Event
738 * @extends YAHOO.util.Anim
739 * @param {HTMLElement | String} el Reference to the element that will be animated
740 * @param {Object} attributes The attribute(s) to be animated.
741 * Each attribute is an object with at minimum a "to" or "by" member defined.
742 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
743 * All attribute names use camelCase.
744 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
745 * @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)
747 var ColorAnim = function(el, attributes, duration, method) {
748 ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
751 ColorAnim.NAME = 'ColorAnim';
753 ColorAnim.DEFAULT_BGCOLOR = '#fff';
756 YAHOO.extend(ColorAnim, Y.Anim);
758 var superclass = ColorAnim.superclass;
759 var proto = ColorAnim.prototype;
761 proto.patterns.color = /color$/i;
762 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
763 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
764 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
765 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari
768 * Attempts to parse the given string and return a 3-tuple.
770 * @param {String} s The string to parse.
771 * @return {Array} The 3-tuple of rgb values.
773 proto.parseColor = function(s) {
774 if (s.length == 3) { return s; }
776 var c = this.patterns.hex.exec(s);
777 if (c && c.length == 4) {
778 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
781 c = this.patterns.rgb.exec(s);
782 if (c && c.length == 4) {
783 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
786 c = this.patterns.hex3.exec(s);
787 if (c && c.length == 4) {
788 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
794 proto.getAttribute = function(attr) {
795 var el = this.getEl();
796 if (this.patterns.color.test(attr) ) {
797 var val = YAHOO.util.Dom.getStyle(el, attr);
800 if (this.patterns.transparent.test(val)) { // bgcolor default
801 var parent = YAHOO.util.Dom.getAncestorBy(el, function(node) {
802 return !that.patterns.transparent.test(val);
806 val = Y.Dom.getStyle(parent, attr);
808 val = ColorAnim.DEFAULT_BGCOLOR;
812 val = superclass.getAttribute.call(this, attr);
818 proto.doMethod = function(attr, start, end) {
821 if ( this.patterns.color.test(attr) ) {
823 for (var i = 0, len = start.length; i < len; ++i) {
824 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
827 val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
830 val = superclass.doMethod.call(this, attr, start, end);
836 proto.setRuntimeAttribute = function(attr) {
837 superclass.setRuntimeAttribute.call(this, attr);
839 if ( this.patterns.color.test(attr) ) {
840 var attributes = this.attributes;
841 var start = this.parseColor(this.runtimeAttributes[attr].start);
842 var end = this.parseColor(this.runtimeAttributes[attr].end);
843 // fix colors if going "by"
844 if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
845 end = this.parseColor(attributes[attr].by);
847 for (var i = 0, len = start.length; i < len; ++i) {
848 end[i] = start[i] + end[i];
852 this.runtimeAttributes[attr].start = start;
853 this.runtimeAttributes[attr].end = end;
857 Y.ColorAnim = ColorAnim;
860 TERMS OF USE - EASING EQUATIONS
861 Open source under the BSD License.
862 Copyright 2001 Robert Penner All rights reserved.
864 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
866 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
867 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
868 * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
870 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
874 * Singleton that determines how an animation proceeds from start to end.
876 * @namespace YAHOO.util
879 YAHOO.util.Easing = {
882 * Uniform speed between points.
884 * @param {Number} t Time value used to compute current value
885 * @param {Number} b Starting value
886 * @param {Number} c Delta between start and end values
887 * @param {Number} d Total length of animation
888 * @return {Number} The computed value for the current animation frame
890 easeNone: function (t, b, c, d) {
895 * Begins slowly and accelerates towards end.
897 * @param {Number} t Time value used to compute current value
898 * @param {Number} b Starting value
899 * @param {Number} c Delta between start and end values
900 * @param {Number} d Total length of animation
901 * @return {Number} The computed value for the current animation frame
903 easeIn: function (t, b, c, d) {
904 return c*(t/=d)*t + b;
908 * Begins quickly and decelerates towards end.
910 * @param {Number} t Time value used to compute current value
911 * @param {Number} b Starting value
912 * @param {Number} c Delta between start and end values
913 * @param {Number} d Total length of animation
914 * @return {Number} The computed value for the current animation frame
916 easeOut: function (t, b, c, d) {
917 return -c *(t/=d)*(t-2) + b;
921 * Begins slowly and decelerates towards end.
923 * @param {Number} t Time value used to compute current value
924 * @param {Number} b Starting value
925 * @param {Number} c Delta between start and end values
926 * @param {Number} d Total length of animation
927 * @return {Number} The computed value for the current animation frame
929 easeBoth: function (t, b, c, d) {
934 return -c/2 * ((--t)*(t-2) - 1) + b;
938 * Begins slowly and accelerates towards end.
939 * @method easeInStrong
940 * @param {Number} t Time value used to compute current value
941 * @param {Number} b Starting value
942 * @param {Number} c Delta between start and end values
943 * @param {Number} d Total length of animation
944 * @return {Number} The computed value for the current animation frame
946 easeInStrong: function (t, b, c, d) {
947 return c*(t/=d)*t*t*t + b;
951 * Begins quickly and decelerates towards end.
952 * @method easeOutStrong
953 * @param {Number} t Time value used to compute current value
954 * @param {Number} b Starting value
955 * @param {Number} c Delta between start and end values
956 * @param {Number} d Total length of animation
957 * @return {Number} The computed value for the current animation frame
959 easeOutStrong: function (t, b, c, d) {
960 return -c * ((t=t/d-1)*t*t*t - 1) + b;
964 * Begins slowly and decelerates towards end.
965 * @method easeBothStrong
966 * @param {Number} t Time value used to compute current value
967 * @param {Number} b Starting value
968 * @param {Number} c Delta between start and end values
969 * @param {Number} d Total length of animation
970 * @return {Number} The computed value for the current animation frame
972 easeBothStrong: function (t, b, c, d) {
974 return c/2*t*t*t*t + b;
977 return -c/2 * ((t-=2)*t*t*t - 2) + b;
981 * Snap in elastic effect.
983 * @param {Number} t Time value used to compute current value
984 * @param {Number} b Starting value
985 * @param {Number} c Delta between start and end values
986 * @param {Number} d Total length of animation
987 * @param {Number} a Amplitude (optional)
988 * @param {Number} p Period (optional)
989 * @return {Number} The computed value for the current animation frame
992 elasticIn: function (t, b, c, d, a, p) {
996 if ( (t /= d) == 1 ) {
1003 if (!a || a < Math.abs(c)) {
1008 var s = p/(2*Math.PI) * Math.asin (c/a);
1011 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
1015 * Snap out elastic effect.
1016 * @method elasticOut
1017 * @param {Number} t Time value used to compute current value
1018 * @param {Number} b Starting value
1019 * @param {Number} c Delta between start and end values
1020 * @param {Number} d Total length of animation
1021 * @param {Number} a Amplitude (optional)
1022 * @param {Number} p Period (optional)
1023 * @return {Number} The computed value for the current animation frame
1025 elasticOut: function (t, b, c, d, a, p) {
1029 if ( (t /= d) == 1 ) {
1036 if (!a || a < Math.abs(c)) {
1041 var s = p/(2*Math.PI) * Math.asin (c/a);
1044 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
1048 * Snap both elastic effect.
1049 * @method elasticBoth
1050 * @param {Number} t Time value used to compute current value
1051 * @param {Number} b Starting value
1052 * @param {Number} c Delta between start and end values
1053 * @param {Number} d Total length of animation
1054 * @param {Number} a Amplitude (optional)
1055 * @param {Number} p Period (optional)
1056 * @return {Number} The computed value for the current animation frame
1058 elasticBoth: function (t, b, c, d, a, p) {
1063 if ( (t /= d/2) == 2 ) {
1071 if ( !a || a < Math.abs(c) ) {
1076 var s = p/(2*Math.PI) * Math.asin (c/a);
1080 return -.5*(a*Math.pow(2,10*(t-=1)) *
1081 Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
1083 return a*Math.pow(2,-10*(t-=1)) *
1084 Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
1089 * Backtracks slightly, then reverses direction and moves to end.
1091 * @param {Number} t Time value used to compute current value
1092 * @param {Number} b Starting value
1093 * @param {Number} c Delta between start and end values
1094 * @param {Number} d Total length of animation
1095 * @param {Number} s Overshoot (optional)
1096 * @return {Number} The computed value for the current animation frame
1098 backIn: function (t, b, c, d, s) {
1099 if (typeof s == 'undefined') {
1102 return c*(t/=d)*t*((s+1)*t - s) + b;
1106 * Overshoots end, then reverses and comes back to end.
1108 * @param {Number} t Time value used to compute current value
1109 * @param {Number} b Starting value
1110 * @param {Number} c Delta between start and end values
1111 * @param {Number} d Total length of animation
1112 * @param {Number} s Overshoot (optional)
1113 * @return {Number} The computed value for the current animation frame
1115 backOut: function (t, b, c, d, s) {
1116 if (typeof s == 'undefined') {
1119 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
1123 * Backtracks slightly, then reverses direction, overshoots end,
1124 * then reverses and comes back to end.
1126 * @param {Number} t Time value used to compute current value
1127 * @param {Number} b Starting value
1128 * @param {Number} c Delta between start and end values
1129 * @param {Number} d Total length of animation
1130 * @param {Number} s Overshoot (optional)
1131 * @return {Number} The computed value for the current animation frame
1133 backBoth: function (t, b, c, d, s) {
1134 if (typeof s == 'undefined') {
1138 if ((t /= d/2 ) < 1) {
1139 return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
1141 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
1145 * Bounce off of start.
1147 * @param {Number} t Time value used to compute current value
1148 * @param {Number} b Starting value
1149 * @param {Number} c Delta between start and end values
1150 * @param {Number} d Total length of animation
1151 * @return {Number} The computed value for the current animation frame
1153 bounceIn: function (t, b, c, d) {
1154 return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
1160 * @param {Number} t Time value used to compute current value
1161 * @param {Number} b Starting value
1162 * @param {Number} c Delta between start and end values
1163 * @param {Number} d Total length of animation
1164 * @return {Number} The computed value for the current animation frame
1166 bounceOut: function (t, b, c, d) {
1167 if ((t/=d) < (1/2.75)) {
1168 return c*(7.5625*t*t) + b;
1169 } else if (t < (2/2.75)) {
1170 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
1171 } else if (t < (2.5/2.75)) {
1172 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
1174 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
1178 * Bounces off start and end.
1179 * @method bounceBoth
1180 * @param {Number} t Time value used to compute current value
1181 * @param {Number} b Starting value
1182 * @param {Number} c Delta between start and end values
1183 * @param {Number} d Total length of animation
1184 * @return {Number} The computed value for the current animation frame
1186 bounceBoth: function (t, b, c, d) {
1188 return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
1190 return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
1196 * Anim subclass for moving elements along a path defined by the "points"
1197 * member of "attributes". All "points" are arrays with x, y coordinates.
1198 * <p>Usage: <code>var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1200 * @namespace YAHOO.util
1201 * @requires YAHOO.util.Anim
1202 * @requires YAHOO.util.AnimMgr
1203 * @requires YAHOO.util.Easing
1204 * @requires YAHOO.util.Bezier
1205 * @requires YAHOO.util.Dom
1206 * @requires YAHOO.util.Event
1207 * @requires YAHOO.util.CustomEvent
1209 * @extends YAHOO.util.ColorAnim
1210 * @param {String | HTMLElement} el Reference to the element that will be animated
1211 * @param {Object} attributes The attribute(s) to be animated.
1212 * Each attribute is an object with at minimum a "to" or "by" member defined.
1213 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1214 * All attribute names use camelCase.
1215 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1216 * @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)
1218 var Motion = function(el, attributes, duration, method) {
1219 if (el) { // dont break existing subclasses not using YAHOO.extend
1220 Motion.superclass.constructor.call(this, el, attributes, duration, method);
1225 Motion.NAME = 'Motion';
1229 YAHOO.extend(Motion, Y.ColorAnim);
1231 var superclass = Motion.superclass;
1232 var proto = Motion.prototype;
1234 proto.patterns.points = /^points$/i;
1236 proto.setAttribute = function(attr, val, unit) {
1237 if ( this.patterns.points.test(attr) ) {
1238 unit = unit || 'px';
1239 superclass.setAttribute.call(this, 'left', val[0], unit);
1240 superclass.setAttribute.call(this, 'top', val[1], unit);
1242 superclass.setAttribute.call(this, attr, val, unit);
1246 proto.getAttribute = function(attr) {
1247 if ( this.patterns.points.test(attr) ) {
1249 superclass.getAttribute.call(this, 'left'),
1250 superclass.getAttribute.call(this, 'top')
1253 val = superclass.getAttribute.call(this, attr);
1259 proto.doMethod = function(attr, start, end) {
1262 if ( this.patterns.points.test(attr) ) {
1263 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
1264 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
1266 val = superclass.doMethod.call(this, attr, start, end);
1271 proto.setRuntimeAttribute = function(attr) {
1272 if ( this.patterns.points.test(attr) ) {
1273 var el = this.getEl();
1274 var attributes = this.attributes;
1276 var control = attributes['points']['control'] || [];
1280 if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
1281 control = [control];
1282 } else { // break reference to attributes.points.control
1284 for (i = 0, len = control.length; i< len; ++i) {
1285 tmp[i] = control[i];
1290 if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
1291 Y.Dom.setStyle(el, 'position', 'relative');
1294 if ( isset(attributes['points']['from']) ) {
1295 Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
1297 else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
1299 start = this.getAttribute('points'); // get actual top & left
1301 // TO beats BY, per SMIL 2.1 spec
1302 if ( isset(attributes['points']['to']) ) {
1303 end = translateValues.call(this, attributes['points']['to'], start);
1305 var pageXY = Y.Dom.getXY(this.getEl());
1306 for (i = 0, len = control.length; i < len; ++i) {
1307 control[i] = translateValues.call(this, control[i], start);
1311 } else if ( isset(attributes['points']['by']) ) {
1312 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
1314 for (i = 0, len = control.length; i < len; ++i) {
1315 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
1319 this.runtimeAttributes[attr] = [start];
1321 if (control.length > 0) {
1322 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
1325 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
1328 superclass.setRuntimeAttribute.call(this, attr);
1332 var translateValues = function(val, start) {
1333 var pageXY = Y.Dom.getXY(this.getEl());
1334 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
1339 var isset = function(prop) {
1340 return (typeof prop !== 'undefined');
1347 * Anim subclass for scrolling elements to a position defined by the "scroll"
1348 * member of "attributes". All "scroll" members are arrays with x, y scroll positions.
1349 * <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1351 * @namespace YAHOO.util
1352 * @requires YAHOO.util.Anim
1353 * @requires YAHOO.util.AnimMgr
1354 * @requires YAHOO.util.Easing
1355 * @requires YAHOO.util.Bezier
1356 * @requires YAHOO.util.Dom
1357 * @requires YAHOO.util.Event
1358 * @requires YAHOO.util.CustomEvent
1359 * @extends YAHOO.util.ColorAnim
1361 * @param {String or HTMLElement} el Reference to the element that will be animated
1362 * @param {Object} attributes The attribute(s) to be animated.
1363 * Each attribute is an object with at minimum a "to" or "by" member defined.
1364 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1365 * All attribute names use camelCase.
1366 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1367 * @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)
1369 var Scroll = function(el, attributes, duration, method) {
1370 if (el) { // dont break existing subclasses not using YAHOO.extend
1371 Scroll.superclass.constructor.call(this, el, attributes, duration, method);
1375 Scroll.NAME = 'Scroll';
1379 YAHOO.extend(Scroll, Y.ColorAnim);
1381 var superclass = Scroll.superclass;
1382 var proto = Scroll.prototype;
1384 proto.doMethod = function(attr, start, end) {
1387 if (attr == 'scroll') {
1389 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
1390 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
1394 val = superclass.doMethod.call(this, attr, start, end);
1399 proto.getAttribute = function(attr) {
1401 var el = this.getEl();
1403 if (attr == 'scroll') {
1404 val = [ el.scrollLeft, el.scrollTop ];
1406 val = superclass.getAttribute.call(this, attr);
1412 proto.setAttribute = function(attr, val, unit) {
1413 var el = this.getEl();
1415 if (attr == 'scroll') {
1416 el.scrollLeft = val[0];
1417 el.scrollTop = val[1];
1419 superclass.setAttribute.call(this, attr, val, unit);
1425 YAHOO.register("animation", YAHOO.util.Anim, {version: "2.9.0", build: "2800"});