2
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3
Code licensed under the BSD License:
4
http://developer.yahoo.net/yui/license.txt
7
YUI.add('anim', function(Y) {
10
* Y.Animation Utility.
15
* Handles animation _queueing and threading.
21
var RUNNING = 'running',
22
START_TIME = 'startTime',
23
ELAPSED_TIME = 'elapsedTime',
26
* @description fires when an animation begins.
27
* @param {Event} ev The start event.
34
* @description fires every frame of the animation.
35
* @param {Event} ev The tween event.
42
* @description fires after the animation completes.
43
* @param {Event} ev The end event.
49
REVERSE = 'reverse', // TODO: cleanup
50
ITERATION_COUNT = 'iterationCount',
59
Y.Anim.superclass.constructor.apply(this, arguments);
60
_instances[Y.stamp(this)] = this;
66
* Regex of properties that should use the default unit.
68
* @property RE_DEFAULT_UNIT
71
Y.Anim.RE_DEFAULT_UNIT = /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i;
74
* The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
76
* @property DEFAULT_UNIT
79
Y.Anim.DEFAULT_UNIT = 'px';
81
Y.Anim.DEFAULT_EASING = function (t, b, c, d) {
82
return c * t / d + b; // linear easing
86
* Bucket for custom getters and setters
93
get: function(anim, attr) {
94
return anim._getOffset(attr);
99
Y.Anim.behaviors.top = Y.Anim.behaviors.left;
102
* The default setter to use when setting object properties.
104
* @property DEFAULT_SETTER
107
Y.Anim.DEFAULT_SETTER = function(anim, att, from, to, elapsed, duration, fn, unit) {
109
anim._node.setStyle(att, fn(elapsed, NUM(from), NUM(to) - NUM(from), duration) + unit);
113
* The default getter to use when getting object properties.
115
* @property DEFAULT_GETTER
118
Y.Anim.DEFAULT_GETTER = function(anim, prop) {
119
return anim._node.getComputedStyle(prop);
124
* The object to be animated.
129
set: function(node) {
130
node = Y.Node.get(node);
133
Y.fail('Y.Anim: invalid node: ' + node);
140
* The length of the animation. Defaults to "1" (second).
141
* @attribute duration
149
* The method that will provide values to the attribute(s) during the animation.
150
* Defaults to "Easing.easeNone".
155
value: Y.Anim.DEFAULT_EASING,
158
if (typeof val === 'string' && Y.Easing) {
159
return Y.Easing[val];
165
* The starting values for the animated properties.
166
* Fields may be strings, numbers, or functions.
167
* If a function is used, the return value becomes the from value.
168
* If no from value is specified, the DEFAULT_GETTER will be used.
175
* The ending values for the animated properties.
176
* Fields may be strings, numbers, or functions.
183
* Date stamp for the first frame of the animation.
184
* @attribute startTime
195
* Current time the animation has been running.
196
* @attribute elapsedTime
207
* Whether or not the animation is currently running.
215
return !!_running[Y.stamp(this)];
222
* The number of times the animation should run
223
* @attribute iterations
232
* The number of iterations that have occurred.
233
* Resets when an animation ends (reaches iteration count or stop() called).
234
* @attribute iterationCount
245
* How iterations of the animation should behave.
246
* Possible values are "normal" and "alternate".
247
* Normal will repeat the animation, alternate will reverse on every other pass.
249
* @attribute direction
254
value: 'normal' // | alternate (fwd on odd, rev on even per spec)
258
* Whether or not the animation is currently paused.
270
* If true, animation begins from last frame
283
* Runs all animation instances.
287
Y.Anim.run = function() {
288
for (var i in _instances) {
289
if (_instances[i].run) {
296
* Pauses all animation instances.
300
Y.Anim.pause = function() {
301
for (var i in _running) { // stop timer if nothing running
302
if (_running[i].pause) {
310
* Stops all animation instances.
314
Y.Anim.stop = function() {
315
for (var i in _running) { // stop timer if nothing running
316
if (_running[i].stop) {
323
Y.Anim._startTimer = function() {
325
_timer = setInterval(Y.Anim._runFrame, 1);
329
Y.Anim._stopTimer = function() {
330
clearInterval(_timer);
335
* Called per Interval to handle each animation frame.
340
Y.Anim._runFrame = function() {
342
for (var anim in _running) {
343
if (_running[anim]._runFrame) {
345
_running[anim]._runFrame();
354
Y.Anim.RE_UNITS = /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/;
358
* Starts or resumes an animation.
359
* percent start time marker.
364
if (!this.get(RUNNING)) {
366
} else if (this.get(PAUSED)) {
373
* Pauses the animation and
374
* freezes it in its current state and time.
375
* Calling run() will continue where it left off.
380
if (this.get(RUNNING)) {
387
* Stops the animation and resets its time.
391
stop: function(finish) {
392
if (this.get(RUNNING) || this.get(PAUSED)) {
401
this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
402
this._actualFrames = 0;
403
if (!this.get(PAUSED)) {
406
_running[Y.stamp(this)] = this;
407
Y.Anim._startTimer();
413
this._set(START_TIME, null);
414
this._set(PAUSED, true);
415
delete _running[Y.stamp(this)];
419
* @description fires when an animation is paused.
420
* @param {Event} ev The pause event.
426
_resume: function() {
427
this._set(PAUSED, false);
428
_running[Y.stamp(this)] = this;
432
* @description fires when an animation is resumed (run from pause).
433
* @param {Event} ev The pause event.
439
_end: function(finish) {
440
this._set(START_TIME, null);
441
this._set(ELAPSED_TIME, 0);
442
this._set(PAUSED, false);
444
delete _running[Y.stamp(this)];
445
this.fire(END, {elapsed: this.get(ELAPSED_TIME)});
448
_runFrame: function() {
449
var attr = this._runtimeAttr,
450
customAttr = Y.Anim.behaviors,
451
easing = attr.easing,
453
t = new Date() - this.get(START_TIME),
454
reversed = this.get(REVERSE),
466
for (var i in attr) {
469
setter = (i in customAttr && 'set' in customAttr[i]) ?
470
customAttr[i].set : Y.Anim.DEFAULT_SETTER;
473
setter(this, i, attribute.from, attribute.to, t, d, easing, attribute.unit);
474
} else { // ensure final frame value is set
475
// TODO: handle keyframes
476
setter(this, i, attribute.from, attribute.to, lastFrame, d, easing, attribute.unit);
481
this._actualFrames += 1;
482
this._set(ELAPSED_TIME, t);
490
_lastFrame: function() {
491
var iter = this.get('iterations'),
492
iterCount = this.get(ITERATION_COUNT);
495
if (iter === 'infinite' || iterCount < iter) {
496
if (this.get('direction') === 'alternate') {
497
this.set(REVERSE, !this.get(REVERSE)); // flip it
501
* @description fires when an animation begins an iteration.
502
* @param {Event} ev The iteration event.
505
this.fire('iteration');
511
this._set(START_TIME, new Date());
512
this._set(ITERATION_COUNT, iterCount);
515
_initAttr: function() {
516
var from = this.get('from') || {},
517
to = this.get('to') || {},
518
dur = this.get('duration') * 1000,
519
node = this.get(NODE),
520
easing = this.get('easing') || {},
522
customAttr = Y.Anim.behaviors,
525
Y.each(to, function(val, name) {
526
if (typeof val === 'function') {
527
val = val.call(this, node);
531
if (begin === undefined) {
532
begin = (name in customAttr && 'get' in customAttr[name]) ?
533
customAttr[name].get(this, name) : Y.Anim.DEFAULT_GETTER(this, name);
534
} else if (typeof begin === 'function') {
535
begin = begin.call(this, node);
538
var mFrom = Y.Anim.RE_UNITS.exec(begin);
539
var mTo = Y.Anim.RE_UNITS.exec(val);
541
begin = mFrom ? mFrom[1] : begin;
542
var end = mTo ? mTo[1] : val,
543
unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units
545
if (!unit && Y.Anim.RE_DEFAULT_UNIT.test(name)) {
546
unit = Y.Anim.DEFAULT_UNIT;
549
if (!begin || !end) {
550
Y.fail('invalid "from" or "to" for "' + name + '"', 'Anim');
561
attr.easing = easing;
565
this._runtimeAttr = attr;
569
// TODO: move to computedStyle? (browsers dont agree on default computed offsets)
570
_getOffset: function(attr) {
571
var node = this._node,
572
val = node.getComputedStyle(attr),
573
get = (attr === 'left') ? 'getX': 'getY',
574
set = (attr === 'left') ? 'setX': 'setY';
576
if (val === 'auto') {
577
var position = node.getStyle('position');
578
if (position === 'absolute' || position === 'fixed') {
590
Y.extend(Y.Anim, Y.Base, proto);
592
TERMS OF USE - EASING EQUATIONS
593
Open source under the BSD License.
594
Copyright 2001 Robert Penner All rights reserved.
596
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
598
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
599
* 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.
600
* 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.
602
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.
606
* The easing module provides methods for customizing
607
* how an animation behaves during each run.
610
* @submodule anim-easing
616
* Uniform speed between points.
618
* @param {Number} t Time value used to compute current value
619
* @param {Number} b Starting value
620
* @param {Number} c Delta between start and end values
621
* @param {Number} d Total length of animation
622
* @return {Number} The computed value for the current animation frame
624
easeNone: function (t, b, c, d) {
629
* Begins slowly and accelerates towards end. (quadratic)
631
* @param {Number} t Time value used to compute current value
632
* @param {Number} b Starting value
633
* @param {Number} c Delta between start and end values
634
* @param {Number} d Total length of animation
635
* @return {Number} The computed value for the current animation frame
637
easeIn: function (t, b, c, d) {
638
return c*(t/=d)*t + b;
642
* Begins quickly and decelerates towards end. (quadratic)
644
* @param {Number} t Time value used to compute current value
645
* @param {Number} b Starting value
646
* @param {Number} c Delta between start and end values
647
* @param {Number} d Total length of animation
648
* @return {Number} The computed value for the current animation frame
650
easeOut: function (t, b, c, d) {
651
return -c *(t/=d)*(t-2) + b;
655
* Begins slowly and decelerates towards end. (quadratic)
657
* @param {Number} t Time value used to compute current value
658
* @param {Number} b Starting value
659
* @param {Number} c Delta between start and end values
660
* @param {Number} d Total length of animation
661
* @return {Number} The computed value for the current animation frame
663
easeBoth: function (t, b, c, d) {
668
return -c/2 * ((--t)*(t-2) - 1) + b;
672
* Begins slowly and accelerates towards end. (quartic)
673
* @method easeInStrong
674
* @param {Number} t Time value used to compute current value
675
* @param {Number} b Starting value
676
* @param {Number} c Delta between start and end values
677
* @param {Number} d Total length of animation
678
* @return {Number} The computed value for the current animation frame
680
easeInStrong: function (t, b, c, d) {
681
return c*(t/=d)*t*t*t + b;
685
* Begins quickly and decelerates towards end. (quartic)
686
* @method easeOutStrong
687
* @param {Number} t Time value used to compute current value
688
* @param {Number} b Starting value
689
* @param {Number} c Delta between start and end values
690
* @param {Number} d Total length of animation
691
* @return {Number} The computed value for the current animation frame
693
easeOutStrong: function (t, b, c, d) {
694
return -c * ((t=t/d-1)*t*t*t - 1) + b;
698
* Begins slowly and decelerates towards end. (quartic)
699
* @method easeBothStrong
700
* @param {Number} t Time value used to compute current value
701
* @param {Number} b Starting value
702
* @param {Number} c Delta between start and end values
703
* @param {Number} d Total length of animation
704
* @return {Number} The computed value for the current animation frame
706
easeBothStrong: function (t, b, c, d) {
708
return c/2*t*t*t*t + b;
711
return -c/2 * ((t-=2)*t*t*t - 2) + b;
715
* Snap in elastic effect.
717
* @param {Number} t Time value used to compute current value
718
* @param {Number} b Starting value
719
* @param {Number} c Delta between start and end values
720
* @param {Number} d Total length of animation
721
* @param {Number} a Amplitude (optional)
722
* @param {Number} p Period (optional)
723
* @return {Number} The computed value for the current animation frame
726
elasticIn: function (t, b, c, d, a, p) {
731
if ( (t /= d) === 1 ) {
738
if (!a || a < Math.abs(c)) {
743
s = p/(2*Math.PI) * Math.asin (c/a);
746
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
750
* Snap out elastic effect.
752
* @param {Number} t Time value used to compute current value
753
* @param {Number} b Starting value
754
* @param {Number} c Delta between start and end values
755
* @param {Number} d Total length of animation
756
* @param {Number} a Amplitude (optional)
757
* @param {Number} p Period (optional)
758
* @return {Number} The computed value for the current animation frame
760
elasticOut: function (t, b, c, d, a, p) {
765
if ( (t /= d) === 1 ) {
772
if (!a || a < Math.abs(c)) {
777
s = p/(2*Math.PI) * Math.asin (c/a);
780
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
784
* Snap both elastic effect.
785
* @method elasticBoth
786
* @param {Number} t Time value used to compute current value
787
* @param {Number} b Starting value
788
* @param {Number} c Delta between start and end values
789
* @param {Number} d Total length of animation
790
* @param {Number} a Amplitude (optional)
791
* @param {Number} p Period (optional)
792
* @return {Number} The computed value for the current animation frame
794
elasticBoth: function (t, b, c, d, a, p) {
800
if ( (t /= d/2) === 2 ) {
808
if ( !a || a < Math.abs(c) ) {
813
s = p/(2*Math.PI) * Math.asin (c/a);
817
return -0.5*(a*Math.pow(2,10*(t-=1)) *
818
Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
820
return a*Math.pow(2,-10*(t-=1)) *
821
Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
826
* Backtracks slightly, then reverses direction and moves to end.
828
* @param {Number} t Time value used to compute current value
829
* @param {Number} b Starting value
830
* @param {Number} c Delta between start and end values
831
* @param {Number} d Total length of animation
832
* @param {Number} s Overshoot (optional)
833
* @return {Number} The computed value for the current animation frame
835
backIn: function (t, b, c, d, s) {
836
if (s == undefined) {
842
return c*(t/=d)*t*((s+1)*t - s) + b;
846
* Overshoots end, then reverses and comes back to end.
848
* @param {Number} t Time value used to compute current value
849
* @param {Number} b Starting value
850
* @param {Number} c Delta between start and end values
851
* @param {Number} d Total length of animation
852
* @param {Number} s Overshoot (optional)
853
* @return {Number} The computed value for the current animation frame
855
backOut: function (t, b, c, d, s) {
856
if (typeof s === 'undefined') {
859
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
863
* Backtracks slightly, then reverses direction, overshoots end,
864
* then reverses and comes back to end.
866
* @param {Number} t Time value used to compute current value
867
* @param {Number} b Starting value
868
* @param {Number} c Delta between start and end values
869
* @param {Number} d Total length of animation
870
* @param {Number} s Overshoot (optional)
871
* @return {Number} The computed value for the current animation frame
873
backBoth: function (t, b, c, d, s) {
874
if (typeof s === 'undefined') {
878
if ((t /= d/2 ) < 1) {
879
return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
881
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
885
* Bounce off of start.
887
* @param {Number} t Time value used to compute current value
888
* @param {Number} b Starting value
889
* @param {Number} c Delta between start and end values
890
* @param {Number} d Total length of animation
891
* @return {Number} The computed value for the current animation frame
893
bounceIn: function (t, b, c, d) {
894
return c - Y.Easing.bounceOut(d-t, 0, c, d) + b;
900
* @param {Number} t Time value used to compute current value
901
* @param {Number} b Starting value
902
* @param {Number} c Delta between start and end values
903
* @param {Number} d Total length of animation
904
* @return {Number} The computed value for the current animation frame
906
bounceOut: function (t, b, c, d) {
907
if ((t/=d) < (1/2.75)) {
908
return c*(7.5625*t*t) + b;
909
} else if (t < (2/2.75)) {
910
return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
911
} else if (t < (2.5/2.75)) {
912
return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
914
return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
918
* Bounces off start and end.
920
* @param {Number} t Time value used to compute current value
921
* @param {Number} b Starting value
922
* @param {Number} c Delta between start and end values
923
* @param {Number} d Total length of animation
924
* @return {Number} The computed value for the current animation frame
926
bounceBoth: function (t, b, c, d) {
928
return Y.Easing.bounceIn(t * 2, 0, c, d) * 0.5 + b;
930
return Y.Easing.bounceOut(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
934
* Adds support for the <code>xy</code> property in <code>from</code> and
935
* <code>to</code> attributes.
943
Y.Anim.behaviors.xy = {
944
set: function(anim, att, from, to, elapsed, duration, fn) {
946
fn(elapsed, NUM(from[0]), NUM(to[0]) - NUM(from[0]), duration),
947
fn(elapsed, NUM(from[1]), NUM(to[1]) - NUM(from[1]), duration)
950
get: function(anim) {
951
return anim._node.getXY();
956
* Adds support for color properties in <code>to</code>
957
* and <code>from</code> attributes.
959
* @submodule anim-color
965
Y.Anim.behaviors.color = {
966
set: function(anim, att, from, to, elapsed, duration, fn) {
967
from = Y.Color.re_RGB.exec(Y.Color.toRGB(from));
968
to = Y.Color.re_RGB.exec(Y.Color.toRGB(to));
970
if (!from || from.length < 3 || !to || to.length < 3) {
971
Y.fail('invalid from or to passed to color behavior');
974
anim._node.setStyle(att, 'rgb(' + [
975
Math.floor(fn(elapsed, NUM(from[1]), NUM(to[1]) - NUM(from[1]), duration)),
976
Math.floor(fn(elapsed, NUM(from[2]), NUM(to[2]) - NUM(from[2]), duration)),
977
Math.floor(fn(elapsed, NUM(from[3]), NUM(to[3]) - NUM(from[3]), duration))
981
// TODO: default bgcolor const
982
get: function(anim, att) {
983
var val = anim._node.getComputedStyle(att);
984
val = (val === 'transparent') ? 'rgb(255, 255, 255)' : val;
989
Y.each(['backgroundColor',
996
Y.Anim.behaviors[v] = Y.Anim.behaviors.color;
1000
* Adds support for the <code>scroll</code> property in <code>to</code>
1001
* and <code>from</code> attributes.
1003
* @submodule anim-scroll
1009
Y.Anim.behaviors.scroll = {
1010
set: function(anim, att, from, to, elapsed, duration, fn) {
1014
fn(elapsed, NUM(from[0]), NUM(to[0]) - NUM(from[0]), duration),
1015
fn(elapsed, NUM(from[1]), NUM(to[1]) - NUM(from[1]), duration)
1019
node.set('scrollLeft', val[0]);
1023
node.set('scrollTop', val[1]);
1026
get: function(anim) {
1027
var node = anim._node;
1028
return [node.get('scrollLeft'), node.get('scrollTop')];
1033
* Adds support for the <code>curve</code> property for the <code>to</code>
1034
* attribute. A curve is zero or more control points and an end point.
1036
* @submodule anim-curve
1040
Y.Anim.behaviors.curve = {
1041
set: function(anim, att, from, to, elapsed, duration, fn) {
1042
from = from.slice.call(from);
1043
to = to.slice.call(to);
1044
var t = fn(elapsed, 0, 100, duration) / 100;
1046
anim._node.setXY(Y.Anim.getBezier(to, t));
1049
get: function(anim, att) {
1050
return anim._node.getXY();
1055
* Get the current position of the animated element based on t.
1056
* Each point is an array of "x" and "y" values (0 = x, 1 = y)
1057
* At least 2 points are required (start and end).
1058
* First point is start. Last point is end.
1059
* Additional control points are optional.
1062
* @param {Array} points An array containing Bezier points
1063
* @param {Number} t A number between 0 and 1 which is the basis for determining current position
1064
* @return {Array} An array containing int x and y member data
1066
Y.Anim.getBezier = function(points, t) {
1067
var n = points.length;
1070
for (var i = 0; i < n; ++i){
1071
tmp[i] = [points[i][0], points[i][1]]; // save input
1074
for (var j = 1; j < n; ++j) {
1075
for (i = 0; i < n - j; ++i) {
1076
tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
1077
tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
1081
return [ tmp[0][0], tmp[0][1] ];
1085
* Binds an Anim instance to a Node instance
1088
* @submodule anim-node-plugin
1091
var NodeFX = function(config) {
1092
var config = Y.merge(config);
1093
config.node = config.owner;
1094
NodeFX.superclass.constructor.apply(this, arguments);
1097
NodeFX.NAME = "nodefx";
1100
Y.extend(NodeFX, Y.Anim);
1102
Y.namespace('plugin');
1103
Y.plugin.NodeFX = NodeFX;
1106
}, '3.0.0pr2' ,{requires:['base', 'node']});