Version 3.18.1

APIs

  • Begin typing in the search box above to see results.
Show:

File: anim/js/anim.js

 /**
 * The Animation Utility provides an API for creating advanced transitions.
 * @module anim
 */
 
 /**
 * Provides the base Anim class, for animating numeric properties.
 *
 * @module anim
 * @submodule anim-base
 */
 
 /**
 * A class for constructing animation instances.
 * @class Anim
 * @for Anim
 * @constructor
 * @extends Base
 */
 
 var RUNNING = 'running',
 START_TIME = 'startTime',
 ELAPSED_TIME = 'elapsedTime',
 /**
 * @for Anim
 * @event start
 * @description fires when an animation begins.
 * @param {Event} ev The start event.
 * @type Event.Custom
 */
 START = 'start',
 
 /**
 * @event tween
 * @description fires every frame of the animation.
 * @param {Event} ev The tween event.
 * @type Event.Custom
 */
 TWEEN = 'tween',
 
 /**
 * @event end
 * @description fires after the animation completes.
 * @param {Event} ev The end event.
 * @type Event.Custom
 */
 END = 'end',
 NODE = 'node',
 PAUSED = 'paused',
 REVERSE = 'reverse', // TODO: cleanup
 ITERATION_COUNT = 'iterationCount',
 
 NUM = Number;
 
 var _running = {},
 _timer;
 
 Y.Anim = function() {
 Y.Anim.superclass.constructor.apply(this, arguments);
 Y.Anim._instances[Y.stamp(this)] = this;
 };
 
 Y.Anim.NAME = 'anim';
 
 Y.Anim._instances = {};
 
 /**
 * Regex of properties that should use the default unit.
 *
 * @property RE_DEFAULT_UNIT
 * @static
 */
 Y.Anim.RE_DEFAULT_UNIT = /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i;
 
 /**
 * The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
 *
 * @property DEFAULT_UNIT
 * @static
 */
 Y.Anim.DEFAULT_UNIT = 'px';
 
 Y.Anim.DEFAULT_EASING = function (t, b, c, d) {
 return c * t / d + b; // linear easing
 };
 
 /**
 * Time in milliseconds passed to setInterval for frame processing
 *
 * @property intervalTime
 * @default 20
 * @static
 */
 Y.Anim._intervalTime = 20;
 
 /**
 * Bucket for custom getters and setters
 *
 * @property behaviors
 * @static
 */
 Y.Anim.behaviors = {
 left: {
 get: function(anim, attr) {
 return anim._getOffset(attr);
 }
 }
 };
 
 Y.Anim.behaviors.top = Y.Anim.behaviors.left;
 
 /**
 * The default setter to use when setting object properties.
 *
 * @property DEFAULT_SETTER
 * @static
 */
 Y.Anim.DEFAULT_SETTER = function(anim, att, from, to, elapsed, duration, fn, unit) {
 var node = anim._node,
 domNode = node._node,
 val = fn(elapsed, NUM(from), NUM(to) - NUM(from), duration);
 
 if (domNode) {
 if ('style' in domNode && (att in domNode.style || att in Y.DOM.CUSTOM_STYLES)) {
 unit = unit || '';
 node.setStyle(att, val + unit);
 } else if ('attributes' in domNode && att in domNode.attributes) {
 node.setAttribute(att, val);
 } else if (att in domNode) {
 domNode[att] = val;
 }
 } else if (node.set) {
 node.set(att, val);
 } else if (att in node) {
 node[att] = val;
 }
 };
 
 /**
 * The default getter to use when getting object properties.
 *
 * @property DEFAULT_GETTER
 * @static
 */
 Y.Anim.DEFAULT_GETTER = function(anim, att) {
 var node = anim._node,
 domNode = node._node,
 val = '';
 
 if (domNode) {
 if ('style' in domNode && (att in domNode.style || att in Y.DOM.CUSTOM_STYLES)) {
 val = node.getComputedStyle(att);
 } else if ('attributes' in domNode && att in domNode.attributes) {
 val = node.getAttribute(att);
 } else if (att in domNode) {
 val = domNode[att];
 }
 } else if (node.get) {
 val = node.get(att);
 } else if (att in node) {
 val = node[att];
 }
 
 return val;
 };
 
 Y.Anim.ATTRS = {
 /**
 * The object to be animated.
 * @attribute node
 * @type Node
 */
 node: {
 setter: function(node) {
 if (node) {
 if (typeof node === 'string' || node.nodeType) {
 node = Y.one(node);
 }
 }
 
 this._node = node;
 if (!node) {
 Y.log(node + ' is not a valid node', 'warn', 'Anim');
 }
 return node;
 }
 },
 
 /**
 * The length of the animation. Defaults to "1" (second).
 * @attribute duration
 * @type NUM
 */
 duration: {
 value: 1
 },
 
 /**
 * The method that will provide values to the attribute(s) during the animation.
 * Defaults to "Easing.easeNone".
 * @attribute easing
 * @type Function
 */
 easing: {
 value: Y.Anim.DEFAULT_EASING,
 
 setter: function(val) {
 if (typeof val === 'string' && Y.Easing) {
 return Y.Easing[val];
 }
 }
 },
 
 /**
 * The starting values for the animated properties.
 *
 * Fields may be strings, numbers, or functions.
 * If a function is used, the return value becomes the from value.
 * If no from value is specified, the DEFAULT_GETTER will be used.
 * Supports any unit, provided it matches the "to" (or default)
 * unit (e.g. `{width: '10em', color: 'rgb(0, 0, 0)', borderColor: '#ccc'}`).
 *
 * If using the default ('px' for length-based units), the unit may be omitted
 * (e.g. `{width: 100}, borderColor: 'ccc'}`, which defaults to pixels
 * and hex, respectively).
 *
 * @attribute from
 * @type Object
 */
 from: {},
 
 /**
 * The ending values for the animated properties.
 *
 * Fields may be strings, numbers, or functions.
 * Supports any unit, provided it matches the "from" (or default)
 * unit (e.g. `{width: '50%', color: 'red', borderColor: '#ccc'}`).
 *
 * If using the default ('px' for length-based units), the unit may be omitted
 * (e.g. `{width: 100, borderColor: 'ccc'}`, which defaults to pixels
 * and hex, respectively).
 *
 * @attribute to
 * @type Object
 */
 to: {},
 
 /**
 * Date stamp for the first frame of the animation.
 * @attribute startTime
 * @type Int
 * @default 0
 * @readOnly
 */
 startTime: {
 value: 0,
 readOnly: true
 },
 
 /**
 * Current time the animation has been running.
 * @attribute elapsedTime
 * @type Int
 * @default 0
 * @readOnly
 */
 elapsedTime: {
 value: 0,
 readOnly: true
 },
 
 /**
 * Whether or not the animation is currently running.
 * @attribute running
 * @type Boolean
 * @default false
 * @readOnly
 */
 running: {
 getter: function() {
 return !!_running[Y.stamp(this)];
 },
 value: false,
 readOnly: true
 },
 
 /**
 * The number of times the animation should run
 * @attribute iterations
 * @type Int
 * @default 1
 */
 iterations: {
 value: 1
 },
 
 /**
 * The number of iterations that have occurred.
 * Resets when an animation ends (reaches iteration count or stop() called).
 * @attribute iterationCount
 * @type Int
 * @default 0
 * @readOnly
 */
 iterationCount: {
 value: 0,
 readOnly: true
 },
 
 /**
 * How iterations of the animation should behave.
 * Possible values are "normal" and "alternate".
 * Normal will repeat the animation, alternate will reverse on every other pass.
 *
 * @attribute direction
 * @type String
 * @default "normal"
 */
 direction: {
 value: 'normal' // | alternate (fwd on odd, rev on even per spec)
 },
 
 /**
 * Whether or not the animation is currently paused.
 * @attribute paused
 * @type Boolean
 * @default false
 * @readOnly
 */
 paused: {
 readOnly: true,
 value: false
 },
 
 /**
 * If true, the `from` and `to` attributes are swapped,
 * and the animation is then run starting from `from`.
 * @attribute reverse
 * @type Boolean
 * @default false
 */
 reverse: {
 value: false
 }
 
 
 };
 
 /**
 * Runs all animation instances.
 * @method run
 * @static
 */
 Y.Anim.run = function() {
 var instances = Y.Anim._instances,
 i;
 for (i in instances) {
 if (instances[i].run) {
 instances[i].run();
 }
 }
 };
 
 /**
 * Pauses all animation instances.
 * @method pause
 * @static
 */
 Y.Anim.pause = function() {
 for (var i in _running) { // stop timer if nothing running
 if (_running[i].pause) {
 _running[i].pause();
 }
 }
 
 Y.Anim._stopTimer();
 };
 
 /**
 * Stops all animation instances.
 * @method stop
 * @static
 */
 Y.Anim.stop = function() {
 for (var i in _running) { // stop timer if nothing running
 if (_running[i].stop) {
 _running[i].stop();
 }
 }
 Y.Anim._stopTimer();
 };
 
 Y.Anim._startTimer = function() {
 if (!_timer) {
 _timer = setInterval(Y.Anim._runFrame, Y.Anim._intervalTime);
 }
 };
 
 Y.Anim._stopTimer = function() {
 clearInterval(_timer);
 _timer = 0;
 };
 
 /**
 * Called per Interval to handle each animation frame.
 * @method _runFrame
 * @private
 * @static
 */
 Y.Anim._runFrame = function() {
 var done = true,
 anim;
 for (anim in _running) {
 if (_running[anim]._runFrame) {
 done = false;
 _running[anim]._runFrame();
 }
 }
 
 if (done) {
 Y.Anim._stopTimer();
 }
 };
 
 Y.Anim.RE_UNITS = /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/;
 
 var proto = {
 /**
 * Starts or resumes an animation.
 * @method run
 * @chainable
 */
 run: function() {
 if (this.get(PAUSED)) {
 this._resume();
 } else if (!this.get(RUNNING)) {
 this._start();
 }
 return this;
 },
 
 /**
 * Pauses the animation and
 * freezes it in its current state and time.
 * Calling run() will continue where it left off.
 * @method pause
 * @chainable
 */
 pause: function() {
 if (this.get(RUNNING)) {
 this._pause();
 }
 return this;
 },
 
 /**
 * Stops the animation and resets its time.
 * @method stop
 * @param {Boolean} finish If true, the animation will move to the last frame
 * @chainable
 */
 stop: function(finish) {
 if (this.get(RUNNING) || this.get(PAUSED)) {
 this._end(finish);
 }
 return this;
 },
 
 _added: false,
 
 _start: function() {
 this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
 this._actualFrames = 0;
 if (!this.get(PAUSED)) {
 this._initAnimAttr();
 }
 _running[Y.stamp(this)] = this;
 Y.Anim._startTimer();
 
 this.fire(START);
 },
 
 _pause: function() {
 this._set(START_TIME, null);
 this._set(PAUSED, true);
 delete _running[Y.stamp(this)];
 
 /**
 * @event pause
 * @description fires when an animation is paused.
 * @param {Event} ev The pause event.
 * @type Event.Custom
 */
 this.fire('pause');
 },
 
 _resume: function() {
 this._set(PAUSED, false);
 _running[Y.stamp(this)] = this;
 this._set(START_TIME, new Date() - this.get(ELAPSED_TIME));
 Y.Anim._startTimer();
 
 /**
 * @event resume
 * @description fires when an animation is resumed (run from pause).
 * @param {Event} ev The pause event.
 * @type Event.Custom
 */
 this.fire('resume');
 },
 
 _end: function(finish) {
 var duration = this.get('duration') * 1000;
 if (finish) { // jump to last frame
 this._runAttrs(duration, duration, this.get(REVERSE));
 }
 
 this._set(START_TIME, null);
 this._set(ELAPSED_TIME, 0);
 this._set(PAUSED, false);
 
 delete _running[Y.stamp(this)];
 this.fire(END, {elapsed: this.get(ELAPSED_TIME)});
 },
 
 _runFrame: function() {
 var d = this._runtimeAttr.duration,
 t = new Date() - this.get(START_TIME),
 reverse = this.get(REVERSE),
 done = (t >= d);
 
 this._runAttrs(t, d, reverse);
 this._actualFrames += 1;
 this._set(ELAPSED_TIME, t);
 
 this.fire(TWEEN);
 if (done) {
 this._lastFrame();
 }
 },
 
 _runAttrs: function(t, d, reverse) {
 var attr = this._runtimeAttr,
 customAttr = Y.Anim.behaviors,
 easing = attr.easing,
 lastFrame = d,
 done = false,
 attribute,
 setter,
 i;
 
 if (t >= d) {
 done = true;
 }
 
 if (reverse) {
 t = d - t;
 lastFrame = 0;
 }
 
 for (i in attr) {
 if (attr[i].to) {
 attribute = attr[i];
 setter = (i in customAttr && 'set' in customAttr[i]) ?
 customAttr[i].set : Y.Anim.DEFAULT_SETTER;
 
 if (!done) {
 setter(this, i, attribute.from, attribute.to, t, d, easing, attribute.unit);
 } else {
 setter(this, i, attribute.from, attribute.to, lastFrame, d, easing, attribute.unit);
 }
 }
 }
 
 
 },
 
 _lastFrame: function() {
 var iter = this.get('iterations'),
 iterCount = this.get(ITERATION_COUNT);
 
 iterCount += 1;
 if (iter === 'infinite' || iterCount < iter) {
 if (this.get('direction') === 'alternate') {
 this.set(REVERSE, !this.get(REVERSE)); // flip it
 }
 /**
 * @event iteration
 * @description fires when an animation begins an iteration.
 * @param {Event} ev The iteration event.
 * @type Event.Custom
 */
 this.fire('iteration');
 } else {
 iterCount = 0;
 this._end();
 }
 
 this._set(START_TIME, new Date());
 this._set(ITERATION_COUNT, iterCount);
 },
 
 _initAnimAttr: function() {
 var from = this.get('from') || {},
 to = this.get('to') || {},
 attr = {
 duration: this.get('duration') * 1000,
 easing: this.get('easing')
 },
 customAttr = Y.Anim.behaviors,
 node = this.get(NODE), // implicit attr init
 unit, begin, end;
 
 Y.each(to, function(val, name) {
 if (typeof val === 'function') {
 val = val.call(this, node);
 }
 
 begin = from[name];
 if (begin === undefined) {
 begin = (name in customAttr && 'get' in customAttr[name]) ?
 customAttr[name].get(this, name) : Y.Anim.DEFAULT_GETTER(this, name);
 } else if (typeof begin === 'function') {
 begin = begin.call(this, node);
 }
 
 var mFrom = Y.Anim.RE_UNITS.exec(begin),
 mTo = Y.Anim.RE_UNITS.exec(val);
 
 begin = mFrom ? mFrom[1] : begin;
 end = mTo ? mTo[1] : val;
 unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units
 
 if (!unit && Y.Anim.RE_DEFAULT_UNIT.test(name)) {
 unit = Y.Anim.DEFAULT_UNIT;
 }
 
 if (!begin || !end) {
 Y.error('invalid "from" or "to" for "' + name + '"', 'Anim');
 return;
 }
 
 attr[name] = {
 from: Y.Lang.isObject(begin) ? Y.clone(begin) : begin,
 to: end,
 unit: unit
 };
 
 }, this);
 
 this._runtimeAttr = attr;
 },
 
 
 // TODO: move to computedStyle? (browsers dont agree on default computed offsets)
 _getOffset: function(attr) {
 var node = this._node,
 val = node.getComputedStyle(attr),
 get = (attr === 'left') ? 'getX': 'getY',
 set = (attr === 'left') ? 'setX': 'setY',
 position;
 
 if (val === 'auto') {
 position = node.getStyle('position');
 if (position === 'absolute' || position === 'fixed') {
 val = node[get]();
 node[set](val);
 } else {
 val = 0;
 }
 }
 
 return val;
 },
 
 destructor: function() {
 delete Y.Anim._instances[Y.stamp(this)];
 }
 };
 
 Y.extend(Y.Anim, Y.Base, proto);
 
 

AltStyle によって変換されたページ (->オリジナル) /