[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/anim-base/ -> anim-base.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('anim-base', function (Y, NAME) {
   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          _timer;
  66  
  67      Y.Anim = function() {
  68          Y.Anim.superclass.constructor.apply(this, arguments);
  69          Y.Anim._instances[Y.stamp(this)] = this;
  70      };
  71  
  72      Y.Anim.NAME = 'anim';
  73  
  74      Y.Anim._instances = {};
  75  
  76      /**
  77       * Regex of properties that should use the default unit.
  78       *
  79       * @property RE_DEFAULT_UNIT
  80       * @static
  81       */
  82      Y.Anim.RE_DEFAULT_UNIT = /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i;
  83  
  84      /**
  85       * The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
  86       *
  87       * @property DEFAULT_UNIT
  88       * @static
  89       */
  90      Y.Anim.DEFAULT_UNIT = 'px';
  91  
  92      Y.Anim.DEFAULT_EASING = function (t, b, c, d) {
  93          return c * t / d + b; // linear easing
  94      };
  95  
  96      /**
  97       * Time in milliseconds passed to setInterval for frame processing
  98       *
  99       * @property intervalTime
 100       * @default 20
 101       * @static
 102       */
 103      Y.Anim._intervalTime = 20;
 104  
 105      /**
 106       * Bucket for custom getters and setters
 107       *
 108       * @property behaviors
 109       * @static
 110       */
 111      Y.Anim.behaviors = {
 112          left: {
 113              get: function(anim, attr) {
 114                  return anim._getOffset(attr);
 115              }
 116          }
 117      };
 118  
 119      Y.Anim.behaviors.top = Y.Anim.behaviors.left;
 120  
 121      /**
 122       * The default setter to use when setting object properties.
 123       *
 124       * @property DEFAULT_SETTER
 125       * @static
 126       */
 127      Y.Anim.DEFAULT_SETTER = function(anim, att, from, to, elapsed, duration, fn, unit) {
 128          var node = anim._node,
 129              domNode = node._node,
 130              val = fn(elapsed, NUM(from), NUM(to) - NUM(from), duration);
 131  
 132          if (domNode) {
 133              if ('style' in domNode && (att in domNode.style || att in Y.DOM.CUSTOM_STYLES)) {
 134                  unit = unit || '';
 135                  node.setStyle(att, val + unit);
 136              } else if ('attributes' in domNode && att in domNode.attributes) {
 137                  node.setAttribute(att, val);
 138              } else if (att in domNode) {
 139                  domNode[att] = val;
 140              }
 141          } else if (node.set) {
 142              node.set(att, val);
 143          } else if (att in node) {
 144              node[att] = val;
 145          }
 146      };
 147  
 148      /**
 149       * The default getter to use when getting object properties.
 150       *
 151       * @property DEFAULT_GETTER
 152       * @static
 153       */
 154      Y.Anim.DEFAULT_GETTER = function(anim, att) {
 155          var node = anim._node,
 156              domNode = node._node,
 157              val = '';
 158  
 159          if (domNode) {
 160              if ('style' in domNode && (att in domNode.style || att in Y.DOM.CUSTOM_STYLES)) {
 161                  val = node.getComputedStyle(att);
 162              } else if ('attributes' in domNode && att in domNode.attributes) {
 163                  val = node.getAttribute(att);
 164              } else if (att in domNode) {
 165                  val = domNode[att];
 166              }
 167          } else if (node.get) {
 168              val = node.get(att);
 169          } else if (att in node) {
 170              val = node[att];
 171          }
 172  
 173          return val;
 174      };
 175  
 176      Y.Anim.ATTRS = {
 177          /**
 178           * The object to be animated.
 179           * @attribute node
 180           * @type Node
 181           */
 182          node: {
 183              setter: function(node) {
 184                  if (node) {
 185                      if (typeof node === 'string' || node.nodeType) {
 186                          node = Y.one(node);
 187                      }
 188                  }
 189  
 190                  this._node = node;
 191                  if (!node) {
 192                  }
 193                  return node;
 194              }
 195          },
 196  
 197          /**
 198           * The length of the animation.  Defaults to "1" (second).
 199           * @attribute duration
 200           * @type NUM
 201           */
 202          duration: {
 203              value: 1
 204          },
 205  
 206          /**
 207           * The method that will provide values to the attribute(s) during the animation.
 208           * Defaults to "Easing.easeNone".
 209           * @attribute easing
 210           * @type Function
 211           */
 212          easing: {
 213              value: Y.Anim.DEFAULT_EASING,
 214  
 215              setter: function(val) {
 216                  if (typeof val === 'string' && Y.Easing) {
 217                      return Y.Easing[val];
 218                  }
 219              }
 220          },
 221  
 222          /**
 223           * The starting values for the animated properties.
 224           *
 225           * Fields may be strings, numbers, or functions.
 226           * If a function is used, the return value becomes the from value.
 227           * If no from value is specified, the DEFAULT_GETTER will be used.
 228           * Supports any unit, provided it matches the "to" (or default)
 229           * unit (e.g. `{width: '10em', color: 'rgb(0, 0, 0)', borderColor: '#ccc'}`).
 230           *
 231           * If using the default ('px' for length-based units), the unit may be omitted
 232           * (e.g. `{width: 100}, borderColor: 'ccc'}`, which defaults to pixels
 233           * and hex, respectively).
 234           *
 235           * @attribute from
 236           * @type Object
 237           */
 238          from: {},
 239  
 240          /**
 241           * The ending values for the animated properties.
 242           *
 243           * Fields may be strings, numbers, or functions.
 244           * Supports any unit, provided it matches the "from" (or default)
 245           * unit (e.g. `{width: '50%', color: 'red', borderColor: '#ccc'}`).
 246           *
 247           * If using the default ('px' for length-based units), the unit may be omitted
 248           * (e.g. `{width: 100, borderColor: 'ccc'}`, which defaults to pixels
 249           * and hex, respectively).
 250           *
 251           * @attribute to
 252           * @type Object
 253           */
 254          to: {},
 255  
 256          /**
 257           * Date stamp for the first frame of the animation.
 258           * @attribute startTime
 259           * @type Int
 260           * @default 0
 261           * @readOnly
 262           */
 263          startTime: {
 264              value: 0,
 265              readOnly: true
 266          },
 267  
 268          /**
 269           * Current time the animation has been running.
 270           * @attribute elapsedTime
 271           * @type Int
 272           * @default 0
 273           * @readOnly
 274           */
 275          elapsedTime: {
 276              value: 0,
 277              readOnly: true
 278          },
 279  
 280          /**
 281           * Whether or not the animation is currently running.
 282           * @attribute running
 283           * @type Boolean
 284           * @default false
 285           * @readOnly
 286           */
 287          running: {
 288              getter: function() {
 289                  return !!_running[Y.stamp(this)];
 290              },
 291              value: false,
 292              readOnly: true
 293          },
 294  
 295          /**
 296           * The number of times the animation should run
 297           * @attribute iterations
 298           * @type Int
 299           * @default 1
 300           */
 301          iterations: {
 302              value: 1
 303          },
 304  
 305          /**
 306           * The number of iterations that have occurred.
 307           * Resets when an animation ends (reaches iteration count or stop() called).
 308           * @attribute iterationCount
 309           * @type Int
 310           * @default 0
 311           * @readOnly
 312           */
 313          iterationCount: {
 314              value: 0,
 315              readOnly: true
 316          },
 317  
 318          /**
 319           * How iterations of the animation should behave.
 320           * Possible values are "normal" and "alternate".
 321           * Normal will repeat the animation, alternate will reverse on every other pass.
 322           *
 323           * @attribute direction
 324           * @type String
 325           * @default "normal"
 326           */
 327          direction: {
 328              value: 'normal' // | alternate (fwd on odd, rev on even per spec)
 329          },
 330  
 331          /**
 332           * Whether or not the animation is currently paused.
 333           * @attribute paused
 334           * @type Boolean
 335           * @default false
 336           * @readOnly
 337           */
 338          paused: {
 339              readOnly: true,
 340              value: false
 341          },
 342  
 343          /**
 344           * If true, the `from` and `to` attributes are swapped, 
 345           * and the animation is then run starting from `from`.
 346           * @attribute reverse
 347           * @type Boolean
 348           * @default false
 349           */
 350          reverse: {
 351              value: false
 352          }
 353  
 354  
 355      };
 356  
 357      /**
 358       * Runs all animation instances.
 359       * @method run
 360       * @static
 361       */
 362      Y.Anim.run = function() {
 363          var instances = Y.Anim._instances,
 364              i;
 365          for (i in instances) {
 366              if (instances[i].run) {
 367                  instances[i].run();
 368              }
 369          }
 370      };
 371  
 372      /**
 373       * Pauses all animation instances.
 374       * @method pause
 375       * @static
 376       */
 377      Y.Anim.pause = function() {
 378          for (var i in _running) { // stop timer if nothing running
 379              if (_running[i].pause) {
 380                  _running[i].pause();
 381              }
 382          }
 383  
 384          Y.Anim._stopTimer();
 385      };
 386  
 387      /**
 388       * Stops all animation instances.
 389       * @method stop
 390       * @static
 391       */
 392      Y.Anim.stop = function() {
 393          for (var i in _running) { // stop timer if nothing running
 394              if (_running[i].stop) {
 395                  _running[i].stop();
 396              }
 397          }
 398          Y.Anim._stopTimer();
 399      };
 400  
 401      Y.Anim._startTimer = function() {
 402          if (!_timer) {
 403              _timer = setInterval(Y.Anim._runFrame, Y.Anim._intervalTime);
 404          }
 405      };
 406  
 407      Y.Anim._stopTimer = function() {
 408          clearInterval(_timer);
 409          _timer = 0;
 410      };
 411  
 412      /**
 413       * Called per Interval to handle each animation frame.
 414       * @method _runFrame
 415       * @private
 416       * @static
 417       */
 418      Y.Anim._runFrame = function() {
 419          var done = true,
 420              anim;
 421          for (anim in _running) {
 422              if (_running[anim]._runFrame) {
 423                  done = false;
 424                  _running[anim]._runFrame();
 425              }
 426          }
 427  
 428          if (done) {
 429              Y.Anim._stopTimer();
 430          }
 431      };
 432  
 433      Y.Anim.RE_UNITS = /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/;
 434  
 435      var proto = {
 436          /**
 437           * Starts or resumes an animation.
 438           * @method run
 439           * @chainable
 440           */
 441          run: function() {
 442              if (this.get(PAUSED)) {
 443                  this._resume();
 444              } else if (!this.get(RUNNING)) {
 445                  this._start();
 446              }
 447              return this;
 448          },
 449  
 450          /**
 451           * Pauses the animation and
 452           * freezes it in its current state and time.
 453           * Calling run() will continue where it left off.
 454           * @method pause
 455           * @chainable
 456           */
 457          pause: function() {
 458              if (this.get(RUNNING)) {
 459                  this._pause();
 460              }
 461              return this;
 462          },
 463  
 464          /**
 465           * Stops the animation and resets its time.
 466           * @method stop
 467           * @param {Boolean} finish If true, the animation will move to the last frame
 468           * @chainable
 469           */
 470          stop: function(finish) {
 471              if (this.get(RUNNING) || this.get(PAUSED)) {
 472                  this._end(finish);
 473              }
 474              return this;
 475          },
 476  
 477          _added: false,
 478  
 479          _start: function() {
 480              this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
 481              this._actualFrames = 0;
 482              if (!this.get(PAUSED)) {
 483                  this._initAnimAttr();
 484              }
 485              _running[Y.stamp(this)] = this;
 486              Y.Anim._startTimer();
 487  
 488              this.fire(START);
 489          },
 490  
 491          _pause: function() {
 492              this._set(START_TIME, null);
 493              this._set(PAUSED, true);
 494              delete _running[Y.stamp(this)];
 495  
 496              /**
 497              * @event pause
 498              * @description fires when an animation is paused.
 499              * @param {Event} ev The pause event.
 500              * @type Event.Custom
 501              */
 502              this.fire('pause');
 503          },
 504  
 505          _resume: function() {
 506              this._set(PAUSED, false);
 507              _running[Y.stamp(this)] = this;
 508              this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
 509              Y.Anim._startTimer();
 510  
 511              /**
 512              * @event resume
 513              * @description fires when an animation is resumed (run from pause).
 514              * @param {Event} ev The pause event.
 515              * @type Event.Custom
 516              */
 517              this.fire('resume');
 518          },
 519  
 520          _end: function(finish) {
 521              var duration = this.get('duration') * 1000;
 522              if (finish) { // jump to last frame
 523                  this._runAttrs(duration, duration, this.get(REVERSE));
 524              }
 525  
 526              this._set(START_TIME, null);
 527              this._set(ELAPSED_TIME, 0);
 528              this._set(PAUSED, false);
 529  
 530              delete _running[Y.stamp(this)];
 531              this.fire(END, {elapsed: this.get(ELAPSED_TIME)});
 532          },
 533  
 534          _runFrame: function() {
 535              var d = this._runtimeAttr.duration,
 536                  t = new Date() - this.get(START_TIME),
 537                  reverse = this.get(REVERSE),
 538                  done = (t >= d);
 539  
 540              this._runAttrs(t, d, reverse);
 541              this._actualFrames += 1;
 542              this._set(ELAPSED_TIME, t);
 543  
 544              this.fire(TWEEN);
 545              if (done) {
 546                  this._lastFrame();
 547              }
 548          },
 549  
 550          _runAttrs: function(t, d, reverse) {
 551              var attr = this._runtimeAttr,
 552                  customAttr = Y.Anim.behaviors,
 553                  easing = attr.easing,
 554                  lastFrame = d,
 555                  done = false,
 556                  attribute,
 557                  setter,
 558                  i;
 559  
 560              if (t >= d) {
 561                  done = true;
 562              }
 563  
 564              if (reverse) {
 565                  t = d - t;
 566                  lastFrame = 0;
 567              }
 568  
 569              for (i in attr) {
 570                  if (attr[i].to) {
 571                      attribute = attr[i];
 572                      setter = (i in customAttr && 'set' in customAttr[i]) ?
 573                              customAttr[i].set : Y.Anim.DEFAULT_SETTER;
 574  
 575                      if (!done) {
 576                          setter(this, i, attribute.from, attribute.to, t, d, easing, attribute.unit);
 577                      } else {
 578                          setter(this, i, attribute.from, attribute.to, lastFrame, d, easing, attribute.unit);
 579                      }
 580                  }
 581              }
 582  
 583  
 584          },
 585  
 586          _lastFrame: function() {
 587              var iter = this.get('iterations'),
 588                  iterCount = this.get(ITERATION_COUNT);
 589  
 590              iterCount += 1;
 591              if (iter === 'infinite' || iterCount < iter) {
 592                  if (this.get('direction') === 'alternate') {
 593                      this.set(REVERSE, !this.get(REVERSE)); // flip it
 594                  }
 595                  /**
 596                  * @event iteration
 597                  * @description fires when an animation begins an iteration.
 598                  * @param {Event} ev The iteration event.
 599                  * @type Event.Custom
 600                  */
 601                  this.fire('iteration');
 602              } else {
 603                  iterCount = 0;
 604                  this._end();
 605              }
 606  
 607              this._set(START_TIME, new Date());
 608              this._set(ITERATION_COUNT, iterCount);
 609          },
 610  
 611          _initAnimAttr: function() {
 612              var from = this.get('from') || {},
 613                  to = this.get('to') || {},
 614                  attr = {
 615                      duration: this.get('duration') * 1000,
 616                      easing: this.get('easing')
 617                  },
 618                  customAttr = Y.Anim.behaviors,
 619                  node = this.get(NODE), // implicit attr init
 620                  unit, begin, end;
 621  
 622              Y.each(to, function(val, name) {
 623                  if (typeof val === 'function') {
 624                      val = val.call(this, node);
 625                  }
 626  
 627                  begin = from[name];
 628                  if (begin === undefined) {
 629                      begin = (name in customAttr && 'get' in customAttr[name])  ?
 630                              customAttr[name].get(this, name) : Y.Anim.DEFAULT_GETTER(this, name);
 631                  } else if (typeof begin === 'function') {
 632                      begin = begin.call(this, node);
 633                  }
 634  
 635                  var mFrom = Y.Anim.RE_UNITS.exec(begin),
 636                      mTo = Y.Anim.RE_UNITS.exec(val);
 637  
 638                  begin = mFrom ? mFrom[1] : begin;
 639                  end = mTo ? mTo[1] : val;
 640                  unit = mTo ? mTo[2] : mFrom ?  mFrom[2] : ''; // one might be zero TODO: mixed units
 641  
 642                  if (!unit && Y.Anim.RE_DEFAULT_UNIT.test(name)) {
 643                      unit = Y.Anim.DEFAULT_UNIT;
 644                  }
 645  
 646                  if (!begin || !end) {
 647                      Y.error('invalid "from" or "to" for "' + name + '"', 'Anim');
 648                      return;
 649                  }
 650  
 651                  attr[name] = {
 652                      from: Y.Lang.isObject(begin) ? Y.clone(begin) : begin,
 653                      to: end,
 654                      unit: unit
 655                  };
 656  
 657              }, this);
 658  
 659              this._runtimeAttr = attr;
 660          },
 661  
 662  
 663          // TODO: move to computedStyle? (browsers dont agree on default computed offsets)
 664          _getOffset: function(attr) {
 665              var node = this._node,
 666                  val = node.getComputedStyle(attr),
 667                  get = (attr === 'left') ? 'getX': 'getY',
 668                  set = (attr === 'left') ? 'setX': 'setY',
 669                  position;
 670  
 671              if (val === 'auto') {
 672                  position = node.getStyle('position');
 673                  if (position === 'absolute' || position === 'fixed') {
 674                      val = node[get]();
 675                      node[set](val);
 676                  } else {
 677                      val = 0;
 678                  }
 679              }
 680  
 681              return val;
 682          },
 683  
 684          destructor: function() {
 685              delete Y.Anim._instances[Y.stamp(this)];
 686          }
 687      };
 688  
 689      Y.extend(Y.Anim, Y.Base, proto);
 690  
 691  
 692  }, '3.17.2', {"requires": ["base-base", "node-style", "color-base"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1