src/cm/media/js/lib/yui/yui3.0.0/build/anim/anim-base-debug.js
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 /*
       
     2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
       
     3 Code licensed under the BSD License:
       
     4 http://developer.yahoo.net/yui/license.txt
       
     5 version: 3.0.0
       
     6 build: 1549
       
     7 */
       
     8 YUI.add('anim-base', function(Y) {
       
     9 
       
    10 /**
       
    11 * The Animation Utility provides an API for creating advanced transitions.
       
    12 * @module anim
       
    13 */
       
    14 
       
    15 /**
       
    16 * Provides the base Anim class, for animating numeric properties.
       
    17 *
       
    18 * @module anim
       
    19 * @submodule anim-base
       
    20 */
       
    21 
       
    22     /**
       
    23      * A class for constructing animation instances.
       
    24      * @class Anim
       
    25      * @for Anim
       
    26      * @constructor
       
    27      * @extends Base
       
    28      */
       
    29 
       
    30     var RUNNING = 'running',
       
    31         START_TIME = 'startTime',
       
    32         ELAPSED_TIME = 'elapsedTime',
       
    33         /**
       
    34         * @for Anim
       
    35         * @event start
       
    36         * @description fires when an animation begins.
       
    37         * @param {Event} ev The start event.
       
    38         * @type Event.Custom
       
    39         */
       
    40         START = 'start',
       
    41 
       
    42         /**
       
    43         * @event tween
       
    44         * @description fires every frame of the animation.
       
    45         * @param {Event} ev The tween event.
       
    46         * @type Event.Custom
       
    47         */
       
    48         TWEEN = 'tween',
       
    49 
       
    50         /**
       
    51         * @event end
       
    52         * @description fires after the animation completes.
       
    53         * @param {Event} ev The end event.
       
    54         * @type Event.Custom
       
    55         */
       
    56         END = 'end',
       
    57         NODE = 'node',
       
    58         PAUSED = 'paused',
       
    59         REVERSE = 'reverse', // TODO: cleanup
       
    60         ITERATION_COUNT = 'iterationCount',
       
    61 
       
    62         NUM = Number;
       
    63 
       
    64     var _running = {},
       
    65         _instances = {},
       
    66         _timer;
       
    67 
       
    68     Y.Anim = function() {
       
    69         Y.Anim.superclass.constructor.apply(this, arguments);
       
    70         _instances[Y.stamp(this)] = this;
       
    71     };
       
    72 
       
    73     Y.Anim.NAME = 'anim';
       
    74 
       
    75     /**
       
    76      * Regex of properties that should use the default unit.
       
    77      *
       
    78      * @property RE_DEFAULT_UNIT
       
    79      * @static
       
    80      */
       
    81     Y.Anim.RE_DEFAULT_UNIT = /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i;
       
    82 
       
    83     /**
       
    84      * The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
       
    85      *
       
    86      * @property DEFAULT_UNIT
       
    87      * @static
       
    88      */
       
    89     Y.Anim.DEFAULT_UNIT = 'px';
       
    90 
       
    91     Y.Anim.DEFAULT_EASING = function (t, b, c, d) {
       
    92         return c * t / d + b; // linear easing
       
    93     };
       
    94 
       
    95     /**
       
    96      * Bucket for custom getters and setters
       
    97      *
       
    98      * @property behaviors
       
    99      * @static
       
   100      */
       
   101     Y.Anim.behaviors = {
       
   102         left: {
       
   103             get: function(anim, attr) {
       
   104                 return anim._getOffset(attr);
       
   105             }
       
   106         }
       
   107     };
       
   108 
       
   109     Y.Anim.behaviors.top = Y.Anim.behaviors.left;
       
   110 
       
   111     /**
       
   112      * The default setter to use when setting object properties.
       
   113      *
       
   114      * @property DEFAULT_SETTER
       
   115      * @static
       
   116      */
       
   117     Y.Anim.DEFAULT_SETTER = function(anim, att, from, to, elapsed, duration, fn, unit) {
       
   118         unit = unit || '';
       
   119         anim._node.setStyle(att, fn(elapsed, NUM(from), NUM(to) - NUM(from), duration) + unit);
       
   120     };
       
   121 
       
   122     /**
       
   123      * The default getter to use when getting object properties.
       
   124      *
       
   125      * @property DEFAULT_GETTER
       
   126      * @static
       
   127      */
       
   128     Y.Anim.DEFAULT_GETTER = function(anim, prop) {
       
   129         return anim._node.getComputedStyle(prop);
       
   130     };
       
   131 
       
   132     Y.Anim.ATTRS = {
       
   133         /**
       
   134          * The object to be animated.
       
   135          * @attribute node
       
   136          * @type Node
       
   137          */
       
   138         node: {
       
   139             setter: function(node) {
       
   140                 node = Y.get(node);
       
   141                 this._node = node;
       
   142                 if (!node) {
       
   143                     Y.log(node + ' is not a valid node', 'warn', 'Anim');
       
   144                 }
       
   145                 return node;
       
   146             }
       
   147         },
       
   148 
       
   149         /**
       
   150          * The length of the animation.  Defaults to "1" (second).
       
   151          * @attribute duration
       
   152          * @type NUM
       
   153          */
       
   154         duration: {
       
   155             value: 1
       
   156         },
       
   157 
       
   158         /**
       
   159          * The method that will provide values to the attribute(s) during the animation. 
       
   160          * Defaults to "Easing.easeNone".
       
   161          * @attribute easing
       
   162          * @type Function
       
   163          */
       
   164         easing: {
       
   165             value: Y.Anim.DEFAULT_EASING,
       
   166 
       
   167             setter: function(val) {
       
   168                 if (typeof val === 'string' && Y.Easing) {
       
   169                     return Y.Easing[val];
       
   170                 }
       
   171             }
       
   172         },
       
   173 
       
   174         /**
       
   175          * The starting values for the animated properties. 
       
   176          * Fields may be strings, numbers, or functions.
       
   177          * If a function is used, the return value becomes the from value.
       
   178          * If no from value is specified, the DEFAULT_GETTER will be used. 
       
   179          * @attribute from
       
   180          * @type Object
       
   181          */
       
   182         from: {},
       
   183 
       
   184         /**
       
   185          * The ending values for the animated properties. 
       
   186          * Fields may be strings, numbers, or functions.
       
   187          * @attribute to
       
   188          * @type Object
       
   189          */
       
   190         to: {},
       
   191 
       
   192         /**
       
   193          * Date stamp for the first frame of the animation.
       
   194          * @attribute startTime
       
   195          * @type Int
       
   196          * @default 0 
       
   197          * @readOnly
       
   198          */
       
   199         startTime: {
       
   200             value: 0,
       
   201             readOnly: true
       
   202         },
       
   203 
       
   204         /**
       
   205          * Current time the animation has been running.
       
   206          * @attribute elapsedTime
       
   207          * @type Int
       
   208          * @default 0 
       
   209          * @readOnly
       
   210          */
       
   211         elapsedTime: {
       
   212             value: 0,
       
   213             readOnly: true
       
   214         },
       
   215 
       
   216         /**
       
   217          * Whether or not the animation is currently running.
       
   218          * @attribute running 
       
   219          * @type Boolean
       
   220          * @default false 
       
   221          * @readOnly
       
   222          */
       
   223         running: {
       
   224             getter: function() {
       
   225                 return !!_running[Y.stamp(this)];
       
   226             },
       
   227             value: false,
       
   228             readOnly: true
       
   229         },
       
   230 
       
   231         /**
       
   232          * The number of times the animation should run 
       
   233          * @attribute iterations
       
   234          * @type Int
       
   235          * @default 1 
       
   236          */
       
   237         iterations: {
       
   238             value: 1
       
   239         },
       
   240 
       
   241         /**
       
   242          * The number of iterations that have occurred.
       
   243          * Resets when an animation ends (reaches iteration count or stop() called). 
       
   244          * @attribute iterationCount
       
   245          * @type Int
       
   246          * @default 0
       
   247          * @readOnly
       
   248          */
       
   249         iterationCount: {
       
   250             value: 0,
       
   251             readOnly: true
       
   252         },
       
   253 
       
   254         /**
       
   255          * How iterations of the animation should behave. 
       
   256          * Possible values are "normal" and "alternate".
       
   257          * Normal will repeat the animation, alternate will reverse on every other pass.
       
   258          *
       
   259          * @attribute direction
       
   260          * @type String
       
   261          * @default "normal"
       
   262          */
       
   263         direction: {
       
   264             value: 'normal' // | alternate (fwd on odd, rev on even per spec)
       
   265         },
       
   266 
       
   267         /**
       
   268          * Whether or not the animation is currently paused.
       
   269          * @attribute paused 
       
   270          * @type Boolean
       
   271          * @default false 
       
   272          * @readOnly
       
   273          */
       
   274         paused: {
       
   275             readOnly: true,
       
   276             value: false
       
   277         },
       
   278 
       
   279         /**
       
   280          * If true, animation begins from last frame
       
   281          * @attribute reverse
       
   282          * @type Boolean
       
   283          * @default false 
       
   284          */
       
   285         reverse: {
       
   286             value: false
       
   287         }
       
   288 
       
   289 
       
   290     };
       
   291 
       
   292     /**
       
   293      * Runs all animation instances.
       
   294      * @method run
       
   295      * @static
       
   296      */    
       
   297     Y.Anim.run = function() {
       
   298         for (var i in _instances) {
       
   299             if (_instances[i].run) {
       
   300                 _instances[i].run();
       
   301             }
       
   302         }
       
   303     };
       
   304 
       
   305     /**
       
   306      * Pauses all animation instances.
       
   307      * @method pause
       
   308      * @static
       
   309      */    
       
   310     Y.Anim.pause = function() {
       
   311         for (var i in _running) { // stop timer if nothing running
       
   312             if (_running[i].pause) {
       
   313                 _running[i].pause();
       
   314             }
       
   315         }
       
   316         Y.Anim._stopTimer();
       
   317     };
       
   318 
       
   319     /**
       
   320      * Stops all animation instances.
       
   321      * @method stop
       
   322      * @static
       
   323      */    
       
   324     Y.Anim.stop = function() {
       
   325         for (var i in _running) { // stop timer if nothing running
       
   326             if (_running[i].stop) {
       
   327                 _running[i].stop();
       
   328             }
       
   329         }
       
   330         Y.Anim._stopTimer();
       
   331     };
       
   332     
       
   333     Y.Anim._startTimer = function() {
       
   334         if (!_timer) {
       
   335             _timer = setInterval(Y.Anim._runFrame, 1);
       
   336         }
       
   337     };
       
   338 
       
   339     Y.Anim._stopTimer = function() {
       
   340         clearInterval(_timer);
       
   341         _timer = 0;
       
   342     };
       
   343 
       
   344     /**
       
   345      * Called per Interval to handle each animation frame.
       
   346      * @method _runFrame
       
   347      * @private
       
   348      * @static
       
   349      */    
       
   350     Y.Anim._runFrame = function() {
       
   351         var done = true;
       
   352         for (var anim in _running) {
       
   353             if (_running[anim]._runFrame) {
       
   354                 done = false;
       
   355                 _running[anim]._runFrame();
       
   356             }
       
   357         }
       
   358 
       
   359         if (done) {
       
   360             Y.Anim._stopTimer();
       
   361         }
       
   362     };
       
   363 
       
   364     Y.Anim.RE_UNITS = /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/;
       
   365 
       
   366     var proto = {
       
   367         /**
       
   368          * Starts or resumes an animation.
       
   369          * percent start time marker.
       
   370          * @method run
       
   371          * @chainable
       
   372          */    
       
   373         run: function() {
       
   374             if (!this.get(RUNNING)) {
       
   375                 this._start();
       
   376             } else if (this.get(PAUSED)) {
       
   377                 this._resume();
       
   378             }
       
   379             return this;
       
   380         },
       
   381 
       
   382         /**
       
   383          * Pauses the animation and
       
   384          * freezes it in its current state and time.
       
   385          * Calling run() will continue where it left off.
       
   386          * @method pause
       
   387          * @chainable
       
   388          */    
       
   389         pause: function() {
       
   390             if (this.get(RUNNING)) {
       
   391                 this._pause();
       
   392             }
       
   393             return this;
       
   394         },
       
   395 
       
   396         /**
       
   397          * Stops the animation and resets its time.
       
   398          * @method stop
       
   399          * @chainable
       
   400          */    
       
   401         stop: function(finish) {
       
   402             if (this.get(RUNNING) || this.get(PAUSED)) {
       
   403                 this._end(finish);
       
   404             }
       
   405             return this;
       
   406         },
       
   407 
       
   408         _added: false,
       
   409 
       
   410         _start: function() {
       
   411             this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
       
   412             this._actualFrames = 0;
       
   413             if (!this.get(PAUSED)) {
       
   414                 this._initAnimAttr();
       
   415             }
       
   416             _running[Y.stamp(this)] = this;
       
   417             Y.Anim._startTimer();
       
   418 
       
   419             this.fire(START);
       
   420         },
       
   421 
       
   422         _pause: function() {
       
   423             this._set(START_TIME, null);
       
   424             this._set(PAUSED, true);
       
   425             delete _running[Y.stamp(this)];
       
   426 
       
   427             /**
       
   428             * @event pause
       
   429             * @description fires when an animation is paused.
       
   430             * @param {Event} ev The pause event.
       
   431             * @type Event.Custom
       
   432             */
       
   433             this.fire('pause');
       
   434         },
       
   435 
       
   436         _resume: function() {
       
   437             this._set(PAUSED, false);
       
   438             _running[Y.stamp(this)] = this;
       
   439 
       
   440             /**
       
   441             * @event resume
       
   442             * @description fires when an animation is resumed (run from pause).
       
   443             * @param {Event} ev The pause event.
       
   444             * @type Event.Custom
       
   445             */
       
   446             this.fire('resume');
       
   447         },
       
   448 
       
   449         _end: function(finish) {
       
   450             this._set(START_TIME, null);
       
   451             this._set(ELAPSED_TIME, 0);
       
   452             this._set(PAUSED, false);
       
   453 
       
   454             delete _running[Y.stamp(this)];
       
   455             this.fire(END, {elapsed: this.get(ELAPSED_TIME)});
       
   456         },
       
   457 
       
   458         _runFrame: function() {
       
   459             var attr = this._runtimeAttr,
       
   460                 customAttr = Y.Anim.behaviors,
       
   461                 easing = attr.easing,
       
   462                 d = attr.duration,
       
   463                 t = new Date() - this.get(START_TIME),
       
   464                 reversed = this.get(REVERSE),
       
   465                 done = (t >= d),
       
   466                 lastFrame = d,
       
   467                 attribute,
       
   468                 setter;
       
   469                 
       
   470             if (reversed) {
       
   471                 t = d - t;
       
   472                 done = (t <= 0);
       
   473                 lastFrame = 0;
       
   474             }
       
   475 
       
   476             for (var i in attr) {
       
   477                 if (attr[i].to) {
       
   478                     attribute = attr[i];
       
   479                     setter = (i in customAttr && 'set' in customAttr[i]) ?
       
   480                             customAttr[i].set : Y.Anim.DEFAULT_SETTER;
       
   481 
       
   482                     if (!done) {
       
   483                         setter(this, i, attribute.from, attribute.to, t, d, easing, attribute.unit); 
       
   484                     } else { // ensure final frame value is set
       
   485                        // TODO: handle keyframes 
       
   486                         setter(this, i, attribute.from, attribute.to, lastFrame, d, easing, attribute.unit); 
       
   487                     }
       
   488                 }
       
   489             }
       
   490 
       
   491             this._actualFrames += 1;
       
   492             this._set(ELAPSED_TIME, t);
       
   493 
       
   494             this.fire(TWEEN);
       
   495             if (done) {
       
   496                 this._lastFrame();
       
   497             }
       
   498         },
       
   499 
       
   500         _lastFrame: function() {
       
   501             var iter = this.get('iterations'),
       
   502                 iterCount = this.get(ITERATION_COUNT);
       
   503 
       
   504             iterCount += 1;
       
   505             if (iter === 'infinite' || iterCount < iter) {
       
   506                 if (this.get('direction') === 'alternate') {
       
   507                     this.set(REVERSE, !this.get(REVERSE)); // flip it
       
   508                 }
       
   509                 /**
       
   510                 * @event iteration
       
   511                 * @description fires when an animation begins an iteration.
       
   512                 * @param {Event} ev The iteration event.
       
   513                 * @type Event.Custom
       
   514                 */
       
   515                 this.fire('iteration');
       
   516             } else {
       
   517                 iterCount = 0;
       
   518                 this._end();
       
   519             }
       
   520 
       
   521             this._set(START_TIME, new Date());
       
   522             this._set(ITERATION_COUNT, iterCount);
       
   523         },
       
   524 
       
   525         _initAnimAttr: function() {
       
   526             var from = this.get('from') || {},
       
   527                 to = this.get('to') || {},
       
   528                 dur = this.get('duration') * 1000,
       
   529                 node = this.get(NODE),
       
   530                 easing = this.get('easing') || {},
       
   531                 attr = {},
       
   532                 customAttr = Y.Anim.behaviors,
       
   533                 unit, begin, end;
       
   534 
       
   535             Y.each(to, function(val, name) {
       
   536                 if (typeof val === 'function') {
       
   537                     val = val.call(this, node);
       
   538                 }
       
   539 
       
   540                 begin = from[name];
       
   541                 if (begin === undefined) {
       
   542                     begin = (name in customAttr && 'get' in customAttr[name])  ?
       
   543                             customAttr[name].get(this, name) : Y.Anim.DEFAULT_GETTER(this, name);
       
   544                 } else if (typeof begin === 'function') {
       
   545                     begin = begin.call(this, node);
       
   546                 }
       
   547 
       
   548                 var mFrom = Y.Anim.RE_UNITS.exec(begin);
       
   549                 var mTo = Y.Anim.RE_UNITS.exec(val);
       
   550 
       
   551                 begin = mFrom ? mFrom[1] : begin;
       
   552                 end = mTo ? mTo[1] : val;
       
   553                 unit = mTo ? mTo[2] : mFrom ?  mFrom[2] : ''; // one might be zero TODO: mixed units
       
   554 
       
   555                 if (!unit && Y.Anim.RE_DEFAULT_UNIT.test(name)) {
       
   556                     unit = Y.Anim.DEFAULT_UNIT;
       
   557                 }
       
   558 
       
   559                 if (!begin || !end) {
       
   560                     Y.error('invalid "from" or "to" for "' + name + '"', 'Anim');
       
   561                     return;
       
   562                 }
       
   563 
       
   564                 attr[name] = {
       
   565                     from: begin,
       
   566                     to: end,
       
   567                     unit: unit
       
   568                 };
       
   569 
       
   570                 attr.duration = dur;
       
   571                 attr.easing = easing;
       
   572 
       
   573             }, this);
       
   574 
       
   575             this._runtimeAttr = attr;
       
   576         },
       
   577 
       
   578 
       
   579         // TODO: move to computedStyle? (browsers dont agree on default computed offsets)
       
   580         _getOffset: function(attr) {
       
   581             var node = this._node,
       
   582                 val = node.getComputedStyle(attr),
       
   583                 get = (attr === 'left') ? 'getX': 'getY',
       
   584                 set = (attr === 'left') ? 'setX': 'setY';
       
   585 
       
   586             if (val === 'auto') {
       
   587                 var position = node.getStyle('position');
       
   588                 if (position === 'absolute' || position === 'fixed') {
       
   589                     val = node[get]();
       
   590                     node[set](val);
       
   591                 } else {
       
   592                     val = 0;
       
   593                 }
       
   594             }
       
   595 
       
   596             return val;
       
   597         }
       
   598     };
       
   599 
       
   600     Y.extend(Y.Anim, Y.Base, proto);
       
   601 
       
   602 
       
   603 }, '3.0.0' ,{requires:['base-base', 'node-style']});