2 Copyright (c) 2006, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * The animation module provides allows effects to be added to HTMLElements.
10 * @requires yahoo, event, dom
15 * Base animation class that provides the interface for building animated effects.
16 * <p>Usage: var myAnim = new YAHOO.util.Anim(el, { width: { from: 10, to: 100 } }, 1, YAHOO.util.Easing.easeOut);</p>
18 * @namespace YAHOO.util
19 * @requires YAHOO.util.AnimMgr
20 * @requires YAHOO.util.Easing
21 * @requires YAHOO.util.Dom
22 * @requires YAHOO.util.Event
23 * @requires YAHOO.util.CustomEvent
25 * @param {String | HTMLElement} el Reference to the element that will be animated
26 * @param {Object} attributes The attribute(s) to be animated.
27 * Each attribute is an object with at minimum a "to" or "by" member defined.
28 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
29 * All attribute names use camelCase.
30 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
31 * @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)
34 YAHOO.util.Anim = function(el, attributes, duration, method) {
36 this.init(el, attributes, duration, method);
40 YAHOO.util.Anim.prototype = {
42 * Provides a readable name for the Anim instance.
46 toString: function() {
47 var el = this.getEl();
48 var id = el.id || el.tagName;
49 return ("Anim " + id);
52 patterns: { // cached for performance
53 noNegatives: /width|height|opacity|padding/i, // keep at zero or above
54 offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default
55 defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default
56 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset
60 * Returns the value computed by the animation's "method".
62 * @param {String} attr The name of the attribute.
63 * @param {Number} start The value this attribute should start from for this animation.
64 * @param {Number} end The value this attribute should end at for this animation.
65 * @return {Number} The Value to be applied to the attribute.
67 doMethod: function(attr, start, end) {
68 return this.method(this.currentFrame, start, end - start, this.totalFrames);
72 * Applies a value to an attribute.
73 * @method setAttribute
74 * @param {String} attr The name of the attribute.
75 * @param {Number} val The value to be applied to the attribute.
76 * @param {String} unit The unit ('px', '%', etc.) of the value.
78 setAttribute: function(attr, val, unit) {
79 if ( this.patterns.noNegatives.test(attr) ) {
80 val = (val > 0) ? val : 0;
83 YAHOO.util.Dom.setStyle(this.getEl(), attr, val + unit);
87 * Returns current value of the attribute.
88 * @method getAttribute
89 * @param {String} attr The name of the attribute.
90 * @return {Number} val The current value of the attribute.
92 getAttribute: function(attr) {
93 var el = this.getEl();
94 var val = YAHOO.util.Dom.getStyle(el, attr);
96 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
97 return parseFloat(val);
100 var a = this.patterns.offsetAttribute.exec(attr) || [];
101 var pos = !!( a[3] ); // top or left
102 var box = !!( a[2] ); // width or height
104 // use offsets for width/height and abs pos top/left
105 if ( box || (YAHOO.util.Dom.getStyle(el, 'position') == 'absolute' && pos) ) {
106 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
107 } else { // default to zero for other 'auto'
115 * Returns the unit to use when none is supplied.
116 * @method getDefaultUnit
117 * @param {attr} attr The name of the attribute.
118 * @return {String} The default unit to be used.
120 getDefaultUnit: function(attr) {
121 if ( this.patterns.defaultUnit.test(attr) ) {
129 * Sets the actual values to be used during the animation. Should only be needed for subclass use.
130 * @method setRuntimeAttribute
131 * @param {Object} attr The attribute object
134 setRuntimeAttribute: function(attr) {
137 var attributes = this.attributes;
139 this.runtimeAttributes[attr] = {};
141 var isset = function(prop) {
142 return (typeof prop !== 'undefined');
145 if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) {
146 return false; // note return; nothing to animate to
149 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
151 // To beats by, per SMIL 2.1 spec
152 if ( isset(attributes[attr]['to']) ) {
153 end = attributes[attr]['to'];
154 } else if ( isset(attributes[attr]['by']) ) {
155 if (start.constructor == Array) {
157 for (var i = 0, len = start.length; i < len; ++i) {
158 end[i] = start[i] + attributes[attr]['by'][i];
161 end = start + attributes[attr]['by'];
165 this.runtimeAttributes[attr].start = start;
166 this.runtimeAttributes[attr].end = end;
168 // set units if needed
169 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
173 * Constructor for Anim instance.
175 * @param {String | HTMLElement} el Reference to the element that will be animated
176 * @param {Object} attributes The attribute(s) to be animated.
177 * Each attribute is an object with at minimum a "to" or "by" member defined.
178 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
179 * All attribute names use camelCase.
180 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
181 * @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)
183 init: function(el, attributes, duration, method) {
185 * Whether or not the animation is running.
186 * @property isAnimated
190 var isAnimated = false;
193 * A Date object that is created when the animation begins.
194 * @property startTime
198 var startTime = null;
201 * The number of frames this animation was able to execute.
202 * @property actualFrames
206 var actualFrames = 0;
209 * The element to be animated.
214 el = YAHOO.util.Dom.get(el);
217 * The collection of attributes to be animated.
218 * Each attribute must have at least a "to" or "by" defined in order to animate.
219 * If "to" is supplied, the animation will end with the attribute at that value.
220 * If "by" is supplied, the animation will end at that value plus its starting value.
221 * If both are supplied, "to" is used, and "by" is ignored.
222 * 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).
223 * @property attributes
226 this.attributes = attributes || {};
229 * The length of the animation. Defaults to "1" (second).
233 this.duration = duration || 1;
236 * The method that will provide values to the attribute(s) during the animation.
237 * Defaults to "YAHOO.util.Easing.easeNone".
241 this.method = method || YAHOO.util.Easing.easeNone;
244 * Whether or not the duration should be treated as seconds.
246 * @property useSeconds
249 this.useSeconds = true; // default to seconds
252 * The location of the current animation on the timeline.
253 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
254 * @property currentFrame
257 this.currentFrame = 0;
260 * The total number of frames to be executed.
261 * In time-based animations, this is used by AnimMgr to ensure the animation finishes on time.
262 * @property totalFrames
265 this.totalFrames = YAHOO.util.AnimMgr.fps;
269 * Returns a reference to the animated element.
271 * @return {HTMLElement}
273 this.getEl = function() { return el; };
276 * Checks whether the element is currently animated.
278 * @return {Boolean} current value of isAnimated.
280 this.isAnimated = function() {
285 * Returns the animation start time.
286 * @method getStartTime
287 * @return {Date} current value of startTime.
289 this.getStartTime = function() {
293 this.runtimeAttributes = {};
298 * Starts the animation by registering it with the animation manager.
301 this.animate = function() {
302 if ( this.isAnimated() ) {
306 this.currentFrame = 0;
308 this.totalFrames = ( this.useSeconds ) ? Math.ceil(YAHOO.util.AnimMgr.fps * this.duration) : this.duration;
310 YAHOO.util.AnimMgr.registerElement(this);
314 * Stops the animation. Normally called by AnimMgr when animation completes.
316 * @param {Boolean} finish (optional) If true, animation will jump to final frame.
318 this.stop = function(finish) {
320 this.currentFrame = this.totalFrames;
321 this._onTween.fire();
323 YAHOO.util.AnimMgr.stop(this);
326 var onStart = function() {
329 this.runtimeAttributes = {};
330 for (var attr in this.attributes) {
331 this.setRuntimeAttribute(attr);
336 startTime = new Date();
340 * Feeds the starting and ending values for each animated attribute to doMethod once per frame, then applies the resulting value to the attribute(s).
344 var onTween = function() {
346 duration: new Date() - this.getStartTime(),
347 currentFrame: this.currentFrame
350 data.toString = function() {
352 'duration: ' + data.duration +
353 ', currentFrame: ' + data.currentFrame
357 this.onTween.fire(data);
359 var runtimeAttributes = this.runtimeAttributes;
361 for (var attr in runtimeAttributes) {
362 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
368 var onComplete = function() {
369 var actual_duration = (new Date() - startTime) / 1000 ;
372 duration: actual_duration,
373 frames: actualFrames,
374 fps: actualFrames / actual_duration
377 data.toString = function() {
379 'duration: ' + data.duration +
380 ', frames: ' + data.frames +
387 this.onComplete.fire(data);
391 * Custom event that fires after onStart, useful in subclassing
394 this._onStart = new YAHOO.util.CustomEvent('_start', this, true);
397 * Custom event that fires when animation begins
398 * Listen via subscribe method (e.g. myAnim.onStart.subscribe(someFunction)
401 this.onStart = new YAHOO.util.CustomEvent('start', this);
404 * Custom event that fires between each frame
405 * Listen via subscribe method (e.g. myAnim.onTween.subscribe(someFunction)
408 this.onTween = new YAHOO.util.CustomEvent('tween', this);
411 * Custom event that fires after onTween
414 this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
417 * Custom event that fires when animation ends
418 * Listen via subscribe method (e.g. myAnim.onComplete.subscribe(someFunction)
421 this.onComplete = new YAHOO.util.CustomEvent('complete', this);
423 * Custom event that fires after onComplete
426 this._onComplete = new YAHOO.util.CustomEvent('_complete', this, true);
428 this._onStart.subscribe(onStart);
429 this._onTween.subscribe(onTween);
430 this._onComplete.subscribe(onComplete);
435 * Handles animation queueing and threading.
436 * Used by Anim and subclasses.
438 * @namespace YAHOO.util
440 YAHOO.util.AnimMgr = new function() {
442 * Reference to the animation Interval.
450 * The current queue of registered animation objects.
458 * The number of active animations.
459 * @property tweenCount
466 * Base frame rate (frames per second).
467 * Arbitrarily high for better x-browser calibration (slower browsers drop more frames).
475 * Interval delay in milliseconds, defaults to fastest possible.
483 * Adds an animation instance to the animation queue.
484 * All animation instances must be registered in order to animate.
485 * @method registerElement
486 * @param {object} tween The Anim instance to be be registered
488 this.registerElement = function(tween) {
489 queue[queue.length] = tween;
491 tween._onStart.fire();
496 * removes an animation instance from the animation queue.
497 * All animation instances must be registered in order to animate.
499 * @param {object} tween The Anim instance to be be registered
500 * @param {Int} index The index of the Anim instance
503 this.unRegister = function(tween, index) {
504 tween._onComplete.fire();
505 index = index || getIndex(tween);
506 if (index != -1) { queue.splice(index, 1); }
509 if (tweenCount <= 0) { this.stop(); }
513 * Starts the animation thread.
514 * Only one thread can run at a time.
517 this.start = function() {
518 if (thread === null) { thread = setInterval(this.run, this.delay); }
522 * Stops the animation thread or a specific animation instance.
524 * @param {object} tween A specific Anim instance to stop (optional)
525 * If no instance given, Manager stops thread and all animations.
527 this.stop = function(tween) {
529 clearInterval(thread);
530 for (var i = 0, len = queue.length; i < len; ++i) {
531 if (queue[i].isAnimated()) {
532 this.unRegister(tween, i);
540 this.unRegister(tween);
545 * Called per Interval to handle each animation frame.
548 this.run = function() {
549 for (var i = 0, len = queue.length; i < len; ++i) {
550 var tween = queue[i];
551 if ( !tween || !tween.isAnimated() ) { continue; }
553 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
555 tween.currentFrame += 1;
557 if (tween.useSeconds) {
560 tween._onTween.fire();
562 else { YAHOO.util.AnimMgr.stop(tween, i); }
566 var getIndex = function(anim) {
567 for (var i = 0, len = queue.length; i < len; ++i) {
568 if (queue[i] == anim) {
569 return i; // note return;
576 * On the fly frame correction to keep animation on time.
577 * @method correctFrame
579 * @param {Object} tween The Anim instance being corrected.
581 var correctFrame = function(tween) {
582 var frames = tween.totalFrames;
583 var frame = tween.currentFrame;
584 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
585 var elapsed = (new Date() - tween.getStartTime());
588 if (elapsed < tween.duration * 1000) { // check if falling behind
589 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
590 } else { // went over duration, so jump to end
591 tweak = frames - (frame + 1);
593 if (tweak > 0 && isFinite(tweak)) { // adjust if needed
594 if (tween.currentFrame + tweak >= frames) {// dont go past last frame
595 tweak = frames - (frame + 1);
598 tween.currentFrame += tweak;
603 * Used to calculate Bezier splines for any number of control points.
605 * @namespace YAHOO.util
608 YAHOO.util.Bezier = new function() {
610 * Get the current position of the animated element based on t.
611 * Each point is an array of "x" and "y" values (0 = x, 1 = y)
612 * At least 2 points are required (start and end).
613 * First point is start. Last point is end.
614 * Additional control points are optional.
615 * @method getPosition
616 * @param {Array} points An array containing Bezier points
617 * @param {Number} t A number between 0 and 1 which is the basis for determining current position
618 * @return {Array} An array containing int x and y member data
620 this.getPosition = function(points, t) {
621 var n = points.length;
624 for (var i = 0; i < n; ++i){
625 tmp[i] = [points[i][0], points[i][1]]; // save input
628 for (var j = 1; j < n; ++j) {
629 for (i = 0; i < n - j; ++i) {
630 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
631 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
635 return [ tmp[0][0], tmp[0][1] ];
641 * Anim subclass for color transitions.
642 * <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,
643 * [255,255,255], or rgb(255,255,255)</p>
645 * @namespace YAHOO.util
646 * @requires YAHOO.util.Anim
647 * @requires YAHOO.util.AnimMgr
648 * @requires YAHOO.util.Easing
649 * @requires YAHOO.util.Bezier
650 * @requires YAHOO.util.Dom
651 * @requires YAHOO.util.Event
653 * @extends YAHOO.util.Anim
654 * @param {HTMLElement | String} el Reference to the element that will be animated
655 * @param {Object} attributes The attribute(s) to be animated.
656 * Each attribute is an object with at minimum a "to" or "by" member defined.
657 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
658 * All attribute names use camelCase.
659 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
660 * @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)
662 YAHOO.util.ColorAnim = function(el, attributes, duration, method) {
663 YAHOO.util.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
666 YAHOO.extend(YAHOO.util.ColorAnim, YAHOO.util.Anim);
670 var superclass = Y.ColorAnim.superclass;
671 var proto = Y.ColorAnim.prototype;
673 proto.toString = function() {
674 var el = this.getEl();
675 var id = el.id || el.tagName;
676 return ("ColorAnim " + id);
679 proto.patterns.color = /color$/i;
680 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
681 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
682 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
683 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/; // need rgba for safari
686 * Attempts to parse the given string and return a 3-tuple.
688 * @param {String} s The string to parse.
689 * @return {Array} The 3-tuple of rgb values.
691 proto.parseColor = function(s) {
692 if (s.length == 3) { return s; }
694 var c = this.patterns.hex.exec(s);
695 if (c && c.length == 4) {
696 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
699 c = this.patterns.rgb.exec(s);
700 if (c && c.length == 4) {
701 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
704 c = this.patterns.hex3.exec(s);
705 if (c && c.length == 4) {
706 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
712 proto.getAttribute = function(attr) {
713 var el = this.getEl();
714 if ( this.patterns.color.test(attr) ) {
715 var val = YAHOO.util.Dom.getStyle(el, attr);
717 if (this.patterns.transparent.test(val)) { // bgcolor default
718 var parent = el.parentNode; // try and get from an ancestor
719 val = Y.Dom.getStyle(parent, attr);
721 while (parent && this.patterns.transparent.test(val)) {
722 parent = parent.parentNode;
723 val = Y.Dom.getStyle(parent, attr);
724 if (parent.tagName.toUpperCase() == 'HTML') {
730 val = superclass.getAttribute.call(this, attr);
736 proto.doMethod = function(attr, start, end) {
739 if ( this.patterns.color.test(attr) ) {
741 for (var i = 0, len = start.length; i < len; ++i) {
742 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
745 val = 'rgb('+Math.floor(val[0])+','+Math.floor(val[1])+','+Math.floor(val[2])+')';
748 val = superclass.doMethod.call(this, attr, start, end);
754 proto.setRuntimeAttribute = function(attr) {
755 superclass.setRuntimeAttribute.call(this, attr);
757 if ( this.patterns.color.test(attr) ) {
758 var attributes = this.attributes;
759 var start = this.parseColor(this.runtimeAttributes[attr].start);
760 var end = this.parseColor(this.runtimeAttributes[attr].end);
761 // fix colors if going "by"
762 if ( typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined' ) {
763 end = this.parseColor(attributes[attr].by);
765 for (var i = 0, len = start.length; i < len; ++i) {
766 end[i] = start[i] + end[i];
770 this.runtimeAttributes[attr].start = start;
771 this.runtimeAttributes[attr].end = end;
775 TERMS OF USE - EASING EQUATIONS
776 Open source under the BSD License.
777 Copyright 2001 Robert Penner All rights reserved.
779 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
781 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
782 * 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.
783 * 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.
785 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.
789 * Singleton that determines how an animation proceeds from start to end.
791 * @namespace YAHOO.util
794 YAHOO.util.Easing = {
797 * Uniform speed between points.
799 * @param {Number} t Time value used to compute current value
800 * @param {Number} b Starting value
801 * @param {Number} c Delta between start and end values
802 * @param {Number} d Total length of animation
803 * @return {Number} The computed value for the current animation frame
805 easeNone: function (t, b, c, d) {
810 * Begins slowly and accelerates towards end. (quadratic)
812 * @param {Number} t Time value used to compute current value
813 * @param {Number} b Starting value
814 * @param {Number} c Delta between start and end values
815 * @param {Number} d Total length of animation
816 * @return {Number} The computed value for the current animation frame
818 easeIn: function (t, b, c, d) {
819 return c*(t/=d)*t + b;
823 * Begins quickly and decelerates towards end. (quadratic)
825 * @param {Number} t Time value used to compute current value
826 * @param {Number} b Starting value
827 * @param {Number} c Delta between start and end values
828 * @param {Number} d Total length of animation
829 * @return {Number} The computed value for the current animation frame
831 easeOut: function (t, b, c, d) {
832 return -c *(t/=d)*(t-2) + b;
836 * Begins slowly and decelerates towards end. (quadratic)
838 * @param {Number} t Time value used to compute current value
839 * @param {Number} b Starting value
840 * @param {Number} c Delta between start and end values
841 * @param {Number} d Total length of animation
842 * @return {Number} The computed value for the current animation frame
844 easeBoth: function (t, b, c, d) {
849 return -c/2 * ((--t)*(t-2) - 1) + b;
853 * Begins slowly and accelerates towards end. (quartic)
854 * @method easeInStrong
855 * @param {Number} t Time value used to compute current value
856 * @param {Number} b Starting value
857 * @param {Number} c Delta between start and end values
858 * @param {Number} d Total length of animation
859 * @return {Number} The computed value for the current animation frame
861 easeInStrong: function (t, b, c, d) {
862 return c*(t/=d)*t*t*t + b;
866 * Begins quickly and decelerates towards end. (quartic)
867 * @method easeOutStrong
868 * @param {Number} t Time value used to compute current value
869 * @param {Number} b Starting value
870 * @param {Number} c Delta between start and end values
871 * @param {Number} d Total length of animation
872 * @return {Number} The computed value for the current animation frame
874 easeOutStrong: function (t, b, c, d) {
875 return -c * ((t=t/d-1)*t*t*t - 1) + b;
879 * Begins slowly and decelerates towards end. (quartic)
880 * @method easeBothStrong
881 * @param {Number} t Time value used to compute current value
882 * @param {Number} b Starting value
883 * @param {Number} c Delta between start and end values
884 * @param {Number} d Total length of animation
885 * @return {Number} The computed value for the current animation frame
887 easeBothStrong: function (t, b, c, d) {
889 return c/2*t*t*t*t + b;
892 return -c/2 * ((t-=2)*t*t*t - 2) + b;
896 * Snap in elastic effect.
898 * @param {Number} t Time value used to compute current value
899 * @param {Number} b Starting value
900 * @param {Number} c Delta between start and end values
901 * @param {Number} d Total length of animation
902 * @param {Number} a Amplitude (optional)
903 * @param {Number} p Period (optional)
904 * @return {Number} The computed value for the current animation frame
907 elasticIn: function (t, b, c, d, a, p) {
911 if ( (t /= d) == 1 ) {
918 if (!a || a < Math.abs(c)) {
923 var s = p/(2*Math.PI) * Math.asin (c/a);
926 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
930 * Snap out elastic effect.
932 * @param {Number} t Time value used to compute current value
933 * @param {Number} b Starting value
934 * @param {Number} c Delta between start and end values
935 * @param {Number} d Total length of animation
936 * @param {Number} a Amplitude (optional)
937 * @param {Number} p Period (optional)
938 * @return {Number} The computed value for the current animation frame
940 elasticOut: function (t, b, c, d, a, p) {
944 if ( (t /= d) == 1 ) {
951 if (!a || a < Math.abs(c)) {
956 var s = p/(2*Math.PI) * Math.asin (c/a);
959 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
963 * Snap both elastic effect.
964 * @method elasticBoth
965 * @param {Number} t Time value used to compute current value
966 * @param {Number} b Starting value
967 * @param {Number} c Delta between start and end values
968 * @param {Number} d Total length of animation
969 * @param {Number} a Amplitude (optional)
970 * @param {Number} p Period (optional)
971 * @return {Number} The computed value for the current animation frame
973 elasticBoth: function (t, b, c, d, a, p) {
978 if ( (t /= d/2) == 2 ) {
986 if ( !a || a < Math.abs(c) ) {
991 var s = p/(2*Math.PI) * Math.asin (c/a);
995 return -.5*(a*Math.pow(2,10*(t-=1)) *
996 Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
998 return a*Math.pow(2,-10*(t-=1)) *
999 Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
1003 * Backtracks slightly, then reverses direction and moves to end.
1005 * @param {Number} t Time value used to compute current value
1006 * @param {Number} b Starting value
1007 * @param {Number} c Delta between start and end values
1008 * @param {Number} d Total length of animation
1009 * @param {Number} s Overshoot (optional)
1010 * @return {Number} The computed value for the current animation frame
1012 backIn: function (t, b, c, d, s) {
1013 if (typeof s == 'undefined') {
1016 return c*(t/=d)*t*((s+1)*t - s) + b;
1020 * Overshoots end, then reverses and comes back to end.
1022 * @param {Number} t Time value used to compute current value
1023 * @param {Number} b Starting value
1024 * @param {Number} c Delta between start and end values
1025 * @param {Number} d Total length of animation
1026 * @param {Number} s Overshoot (optional)
1027 * @return {Number} The computed value for the current animation frame
1029 backOut: function (t, b, c, d, s) {
1030 if (typeof s == 'undefined') {
1033 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
1037 * Backtracks slightly, then reverses direction, overshoots end,
1038 * then reverses and comes back to end.
1040 * @param {Number} t Time value used to compute current value
1041 * @param {Number} b Starting value
1042 * @param {Number} c Delta between start and end values
1043 * @param {Number} d Total length of animation
1044 * @param {Number} s Overshoot (optional)
1045 * @return {Number} The computed value for the current animation frame
1047 backBoth: function (t, b, c, d, s) {
1048 if (typeof s == 'undefined') {
1052 if ((t /= d/2 ) < 1) {
1053 return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
1055 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
1059 * Bounce off of start.
1061 * @param {Number} t Time value used to compute current value
1062 * @param {Number} b Starting value
1063 * @param {Number} c Delta between start and end values
1064 * @param {Number} d Total length of animation
1065 * @return {Number} The computed value for the current animation frame
1067 bounceIn: function (t, b, c, d) {
1068 return c - YAHOO.util.Easing.bounceOut(d-t, 0, c, d) + b;
1074 * @param {Number} t Time value used to compute current value
1075 * @param {Number} b Starting value
1076 * @param {Number} c Delta between start and end values
1077 * @param {Number} d Total length of animation
1078 * @return {Number} The computed value for the current animation frame
1080 bounceOut: function (t, b, c, d) {
1081 if ((t/=d) < (1/2.75)) {
1082 return c*(7.5625*t*t) + b;
1083 } else if (t < (2/2.75)) {
1084 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
1085 } else if (t < (2.5/2.75)) {
1086 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
1088 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
1092 * Bounces off start and end.
1093 * @method bounceBoth
1094 * @param {Number} t Time value used to compute current value
1095 * @param {Number} b Starting value
1096 * @param {Number} c Delta between start and end values
1097 * @param {Number} d Total length of animation
1098 * @return {Number} The computed value for the current animation frame
1100 bounceBoth: function (t, b, c, d) {
1102 return YAHOO.util.Easing.bounceIn(t*2, 0, c, d) * .5 + b;
1104 return YAHOO.util.Easing.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
1110 * Anim subclass for moving elements along a path defined by the "points"
1111 * member of "attributes". All "points" are arrays with x, y coordinates.
1112 * <p>Usage: <code>var myAnim = new YAHOO.util.Motion(el, { points: { to: [800, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1114 * @namespace YAHOO.util
1115 * @requires YAHOO.util.Anim
1116 * @requires YAHOO.util.AnimMgr
1117 * @requires YAHOO.util.Easing
1118 * @requires YAHOO.util.Bezier
1119 * @requires YAHOO.util.Dom
1120 * @requires YAHOO.util.Event
1121 * @requires YAHOO.util.CustomEvent
1123 * @extends YAHOO.util.Anim
1124 * @param {String | HTMLElement} el Reference to the element that will be animated
1125 * @param {Object} attributes The attribute(s) to be animated.
1126 * Each attribute is an object with at minimum a "to" or "by" member defined.
1127 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1128 * All attribute names use camelCase.
1129 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1130 * @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)
1132 YAHOO.util.Motion = function(el, attributes, duration, method) {
1133 if (el) { // dont break existing subclasses not using YAHOO.extend
1134 YAHOO.util.Motion.superclass.constructor.call(this, el, attributes, duration, method);
1138 YAHOO.extend(YAHOO.util.Motion, YAHOO.util.ColorAnim);
1142 var superclass = Y.Motion.superclass;
1143 var proto = Y.Motion.prototype;
1145 proto.toString = function() {
1146 var el = this.getEl();
1147 var id = el.id || el.tagName;
1148 return ("Motion " + id);
1151 proto.patterns.points = /^points$/i;
1153 proto.setAttribute = function(attr, val, unit) {
1154 if ( this.patterns.points.test(attr) ) {
1155 unit = unit || 'px';
1156 superclass.setAttribute.call(this, 'left', val[0], unit);
1157 superclass.setAttribute.call(this, 'top', val[1], unit);
1159 superclass.setAttribute.call(this, attr, val, unit);
1163 proto.getAttribute = function(attr) {
1164 if ( this.patterns.points.test(attr) ) {
1166 superclass.getAttribute.call(this, 'left'),
1167 superclass.getAttribute.call(this, 'top')
1170 val = superclass.getAttribute.call(this, attr);
1176 proto.doMethod = function(attr, start, end) {
1179 if ( this.patterns.points.test(attr) ) {
1180 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
1181 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
1183 val = superclass.doMethod.call(this, attr, start, end);
1188 proto.setRuntimeAttribute = function(attr) {
1189 if ( this.patterns.points.test(attr) ) {
1190 var el = this.getEl();
1191 var attributes = this.attributes;
1193 var control = attributes['points']['control'] || [];
1197 if (control.length > 0 && !(control[0] instanceof Array) ) { // could be single point or array of points
1198 control = [control];
1199 } else { // break reference to attributes.points.control
1201 for (i = 0, len = control.length; i< len; ++i) {
1202 tmp[i] = control[i];
1207 if (Y.Dom.getStyle(el, 'position') == 'static') { // default to relative
1208 Y.Dom.setStyle(el, 'position', 'relative');
1211 if ( isset(attributes['points']['from']) ) {
1212 Y.Dom.setXY(el, attributes['points']['from']); // set position to from point
1214 else { Y.Dom.setXY( el, Y.Dom.getXY(el) ); } // set it to current position
1216 start = this.getAttribute('points'); // get actual top & left
1218 // TO beats BY, per SMIL 2.1 spec
1219 if ( isset(attributes['points']['to']) ) {
1220 end = translateValues.call(this, attributes['points']['to'], start);
1222 var pageXY = Y.Dom.getXY(this.getEl());
1223 for (i = 0, len = control.length; i < len; ++i) {
1224 control[i] = translateValues.call(this, control[i], start);
1228 } else if ( isset(attributes['points']['by']) ) {
1229 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
1231 for (i = 0, len = control.length; i < len; ++i) {
1232 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
1236 this.runtimeAttributes[attr] = [start];
1238 if (control.length > 0) {
1239 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
1242 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
1245 superclass.setRuntimeAttribute.call(this, attr);
1249 var translateValues = function(val, start) {
1250 var pageXY = Y.Dom.getXY(this.getEl());
1251 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
1256 var isset = function(prop) {
1257 return (typeof prop !== 'undefined');
1262 * Anim subclass for scrolling elements to a position defined by the "scroll"
1263 * member of "attributes". All "scroll" members are arrays with x, y scroll positions.
1264 * <p>Usage: <code>var myAnim = new YAHOO.util.Scroll(el, { scroll: { to: [0, 800] } }, 1, YAHOO.util.Easing.easeOut);</code></p>
1266 * @namespace YAHOO.util
1267 * @requires YAHOO.util.Anim
1268 * @requires YAHOO.util.AnimMgr
1269 * @requires YAHOO.util.Easing
1270 * @requires YAHOO.util.Bezier
1271 * @requires YAHOO.util.Dom
1272 * @requires YAHOO.util.Event
1273 * @requires YAHOO.util.CustomEvent
1274 * @extends YAHOO.util.Anim
1276 * @param {String or HTMLElement} el Reference to the element that will be animated
1277 * @param {Object} attributes The attribute(s) to be animated.
1278 * Each attribute is an object with at minimum a "to" or "by" member defined.
1279 * Additional optional members are "from" (defaults to current value), "units" (defaults to "px").
1280 * All attribute names use camelCase.
1281 * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based
1282 * @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)
1284 YAHOO.util.Scroll = function(el, attributes, duration, method) {
1285 if (el) { // dont break existing subclasses not using YAHOO.extend
1286 YAHOO.util.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
1290 YAHOO.extend(YAHOO.util.Scroll, YAHOO.util.ColorAnim);
1294 var superclass = Y.Scroll.superclass;
1295 var proto = Y.Scroll.prototype;
1297 proto.toString = function() {
1298 var el = this.getEl();
1299 var id = el.id || el.tagName;
1300 return ("Scroll " + id);
1303 proto.doMethod = function(attr, start, end) {
1306 if (attr == 'scroll') {
1308 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
1309 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
1313 val = superclass.doMethod.call(this, attr, start, end);
1318 proto.getAttribute = function(attr) {
1320 var el = this.getEl();
1322 if (attr == 'scroll') {
1323 val = [ el.scrollLeft, el.scrollTop ];
1325 val = superclass.getAttribute.call(this, attr);
1331 proto.setAttribute = function(attr, val, unit) {
1332 var el = this.getEl();
1334 if (attr == 'scroll') {
1335 el.scrollLeft = val[0];
1336 el.scrollTop = val[1];
1338 superclass.setAttribute.call(this, attr, val, unit);