/** * @class Ext.fx.Anim * Animation instance... */ Ext.define('Ext.fx.Anim', { /* Begin Definitions */ mixins: { observable: 'Ext.util.Observable' }, requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.PseudoEasing', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropHandler'], /* End Definitions */ isAnimation: true,
/** * @cfg {Number} duration * Time in milliseconds for the animation to last. Defaults to 250. */ duration: 250,
/** * @cfg {Number} delay * Time to delay before starting the animation. Defaults to 0. */ delay: 0, /* private used to track a delayed starting time */ delayStart: 0,
/** * @cfg {String} easing *

A valid Ext.fx.Easing or Ext.fx.EasingPseudo value for the effect. * Easing is now calculated exclusively with the use of cubic-bezier curves and follows the * CSS3 * specification for 'transition-timing-function'. Defaults to ease

*

Standard CSS3 Easing Values:

*
* PseudoEasing combines multiple cubic-bezier curves and creates an Ext.fx.Animation to achieve more complex effects. *

Extended Pseudo Easing Values:

*
*/ easing: 'ease', /** * @private */ damper: 1, /** * @private */ bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
/** * @cfg {Boolean} reverse * Run the animation from the end to the beginning * Defaults to false. */ reverse: false,
/** * Flag to determine if the animation has started * @property running * @type boolean */ running: false,
/** * Flag to determine if the animation is paused. Only set this to true if you need to * keep the Anim instance around to be unpaused later; otherwise call {@link #end}. * @property paused * @type boolean */ paused: false,
/** * @cfg {int} iterations * Number of times to execute the animation. Defaults to 1. */ iterations: 1, alternate: false,
/** * Current iteration the animation is running. * @property currentIteration * @type int */ currentIteration: 0,
/** * Starting time of the animation. * @property startTime * @type Date */ startTime: 0,
/** * Elapsed time of the animation. * @property elapsedTime * @type Date */ elapsedTime: 0,
/** * Contains a cache of the interpolators to be used. * @property propHandlers * @type Object */ propHandlers: {},
/** * @cfg {string/object} target * The Ext.fx.target to apply the animation to. */
/** * @cfg {Object} from * An object containing property/value pairs for the beginning of the animation. If not specified, the current state of the * Ext.fx.target will be used. For example:

from : {
    opactiy: 0,       // Transparent
    color: '#ffffff', // White
    left: 0
}
*/
/** * @cfg {Object} to * An object containing property/value pairs for the end of the animation. For example:

 to : {
     opactiy: 1,       // Opaque
     color: '#00ff00', // Green
     left: 500
 }
 
*/ // @private constructor: function(config) { var me = this; // If keyframes are passed, they really want an Animator instead. if (config.keyframes) { return new Ext.fx.Animator(config); } // Create a PseudoEasing Animation if the easing property matches if (Ext.fx.PseudoEasing[config.easing]) { // OOgly, clean me up. return new Ext.fx.Animator(Ext.apply(config, { keyframes: Ext.decode(Ext.encode(Ext.fx.PseudoEasing[config.easing])) })); } config = Ext.apply(me, config); if (me.from == undefined) { me.from = {}; } me.config = config; me.target = Ext.fx.Manager.createTarget(me.target); me.easingFn = Ext.fx.Easing[me.easing]; // If not a pre-defined curve, try a cubic-bezier if (!me.easingFn) { me.easingFn = String(v.easing).match(me.bezierRE); if (me.easingFn && me.easingFn.length == 5) { var curve = me.easingFn; me.easingFn = Ext.fx.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]); } } me.id = Ext.id(null, 'ext-anim-'); Ext.fx.Manager.addAnim(me); me.addEvents(
/** * @event beforeanimate * Fires before the animation starts. A handler can return false to cancel the animation. * @param {Ext.fx.Anim} this */ 'beforeanimate',
/** * @event afteranimate * Fires when the animation is complete. * @param {Ext.fx.Anim} this * @param {Date} startTime * @param {Date} ellapsedTime */ 'afteranimate' ); me.mixins.observable.constructor.call(me, config); if (config.callback) { me.on('afteranimate', config.callback, config.scope); } return me; }, /** * @private * Helper to the target */ setAttr: function(attr, value) { return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value); }, /* * @private * Set up the initial currentAttrs hash. */ initAttrs: function() { var me = this, from = me.from, to = me.to, initialFrom = me.initialFrom || {}, out = {}, start, end, propHandler, attr; for (attr in to) { if (to.hasOwnProperty(attr)) { start = me.target.getAttr(attr, from[attr]); end = to[attr]; // Use default (numeric) property handler if (!Ext.fx.PropHandler[attr]) { if (Ext.isObject(end)) { propHandler = me.propHandlers[attr] = Ext.fx.PropHandler.object; } else { propHandler = me.propHandlers[attr] = Ext.fx.PropHandler.defaultHandler; } } // Use custom handler else { propHandler = me.propHandlers[attr] = Ext.fx.PropHandler[attr]; } out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr]); } } me.currentAttrs = out; }, /* * @private * Fires beforeanimate and sets the running flag. */ start: function(startTime) { var me = this, delay = me.delay, delayStart = me.delayStart, delayDelta; if (delay) { if (!delayStart) { me.delayStart = startTime; return; } else { delayDelta = startTime - delayStart; if (delayDelta < delay) { return; } else { // Compensate for frame delay; startTime = new Date(delayStart.getTime() + delay); } } } if (me.fireEvent('beforeanimate', me) !== false) { me.startTime = startTime - me.elapsedTime; if (!me.paused && !me.currentAttrs) { me.initAttrs(); } me.running = true; } }, /* * @private * Calculate attribute value at the passed timestamp. * @returns a hash of the new attributes. */ runAnim: function(timestamp) { var me = this, attrs = me.currentAttrs, duration = me.duration, easingFn = me.easingFn, propHandlers = me.propHandlers, ret = {}, easing, values, attr; if (timestamp >= duration) { timestamp = duration; } if (me.reverse) { timestamp = duration - timestamp; } for (attr in attrs) { if (attrs.hasOwnProperty(attr)) { values = attrs[attr]; easing = easingFn(timestamp / duration); ret[attr] = propHandlers[attr].set(values, easing); } } return ret; }, /* * @private * Perform lastFrame cleanup and handle iterations * @returns a hash of the new attributes. */ lastFrame: function() { var me = this, iter = me.iterations, iterCount = me.currentIteration; iterCount++; if (iterCount < iter) { if (me.alternate) { me.reverse = !me.reverse; } } else { iterCount = 0; me.end(); } me.startTime = new Date(); me.currentIteration = iterCount; // Turn off paused for CSS3 Transitions me.paused = false; }, /* * Fire afteranimate event and end the animation. Usually called automatically when the * animation reaches its final frame, but can also be called manually to pre-emptively * stop and destroy the running animation. */ end: function() { var me = this; me.fireEvent('afteranimate', me, me.startTime, me.elapsedTime); me.startTime = 0; me.elapsedTime = 0; me.paused = false; me.running = false; Ext.fx.Manager.removeAnim(me); } }); // Set flag to indicate that Fx is available. Class might not be available immediately. Ext.enableFx = true;