/** * @class Ext.fx.Animator * Animation instance */ Ext.define('Ext.fx.Animator', { /* Begin Definitions */ mixins: { observable: 'Ext.util.Observable' }, requires: ['Ext.fx.Manager'], /* End Definitions */ /** * @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, /** * @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. **
- ease: The ease function is equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0).
*- linear: The linear function is equivalent to cubic-bezier(0.0, 0.0, 1.0, 1.0).
*- ease-in: The ease-in function is equivalent to cubic-bezier(0.42, 0, 1.0, 1.0).
*- ease-out: The ease-out function is equivalent to cubic-bezier(0, 0, 0.58, 1.0).
*- ease-in-out: The ease-in-out function is equivalent to cubic-bezier(0.42, 0, 0.58, 1.0)
*- cubic-bezier: Specifies a cubic-bezier curve. The four values specify points P1 and P2 of * the curve as (x1, y1, x2, y2). All values must be in the range [0, 1] or the definition is invalid.
*Extended Pseudo Easing Values:
**/ easing: 'ease', /** * @private */ damper: 1, /** * @cfg {Number} iterations * Number of times to execute the animation. Defaults to 1. */ iterations: 1, /** * Current keyframe step of the animation. * @property keyframeStep * @type Number */ keyframeStep: 0, /** * @private */ animKeyFramesRE: /^(from|to|\d+%?)$/, /** * @cfg {Ext.fx.target} target * The Ext.fx.target to apply the animation to. If not specified during initialization, this can be passed to the applyAnimator * method to apply the same animation to many targets. */ /** * @cfg {Object} keyframes * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to' * is considered '100%'.Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using * "from" or "to". A keyframe declaration without these keyframe selectors is invalid and will not be available for * animation. The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:*
- back-in
*- back-out
*- bounce-in
*- bounce-out
*- elastic-in
*- elastic-out
**/ constructor: function(config) { config = Ext.apply(this, config || {}); this.config = config; this.id = Ext.id(null, 'ext-animator-'); this.addEvents( /** * @event beforeanimate * Fires before the animation starts. A handler can return false to cancel the animation. * @param {Ext.fx.Animator} this */ 'beforeanimate', /** * @event keyframe * Fires at each keyframe. * @param {Ext.fx.Animator} this * @param {Number} keyframe step number */ 'keyframe', /** * @event afteranimate * Fires when the animation is complete. * @param {Ext.fx.Animator} this * @param {Date} startTime * @param {Date} elapsedTime */ 'afteranimate' ); this.mixins.observable.constructor.call(this, config); this.timeline = []; this.createTimeline(this.keyframes); if (this.target) { this.applyAnimator(this.target); } }, /** * @private */ sorter: function (a, b) { return a.pct - b.pct; }, /** * @private * Takes the given keyframe configuration object and converts it into an ordered array with the passed attributes per keyframe * or applying the 'to' configuration to all keyframes. Also calculates the proper animation duration per keyframe. */ createTimeline: function(keyframes) { var attrs = [], attr, to = this.to || {}, prevMs, ms, i, ln, pct, anim, nextAnim, duration = this.duration; if (keyframes.isPseudoEasing) { this.isPseudoEasing = true; } for (pct in keyframes) { if (keyframes.hasOwnProperty(pct) && this.animKeyFramesRE.test(pct)) { attr = {attrs: Ext.apply(keyframes[pct], to)}; // CSS3 spec allow for from/to to be specified. if (pct == "from") { pct = 0; } else if (pct == "to") { pct = 100; } // convert % values into integers attr.pct = parseInt(pct, 10); attrs.push(attr); } } // Sort by pct property attrs.sort(this.sorter); // Only an end //if (attrs[0].pct) { // attrs.unshift({pct: 0, attrs: element.attrs}); //} ln = attrs.length; for (i = 0; i < ln; i++) { prevMs = (attrs[i - 1]) ? duration * (attrs[i - 1].pct / 100) : 0; ms = duration * (attrs[i].pct / 100); this.timeline.push({ duration: ms - prevMs, attrs: attrs[i].attrs }); } }, /** * Applies animation to the Ext.fx.target * @param target * @type string/object */ applyAnimator: function(target) { target = Ext.fx.Manager.createTarget(target); var anims = [], anim, timeline = this.timeline, reverse = this.reverse, isPseudoEasing = this.isPseudoEasing, ln = timeline.length, easing, damper, initial, attrs, lastAttrs, i; if (this.fireEvent('beforeanimate', this) !== false) { for (i = 0; i < ln; i++) { anim = timeline[i]; attrs = anim.attrs; easing = attrs.easing || this.easing; damper = attrs.damper || this.damper; delete attrs.easing; delete attrs.damper; anim = new Ext.fx.Anim({ target: target, easing: easing, damper: damper, initialFrom: isPseudoEasing && initial, duration: anim.duration, reverse: reverse, paused: true, from: lastAttrs, to: attrs }); if (!i) { anim.initAttrs(); initial = anim.currentAttrs; } if (!isPseudoEasing) { lastAttrs = Ext.apply({}, attrs, lastAttrs); } anims.push(anim); } if (reverse) { anims.reverse(); } for (i = 0; i < ln - 1; i++) { anim = anims[i]; anim.nextAnim = anims[i + 1]; anim.on('afteranimate', function() { this.nextAnim.paused = false; }); anim.on('afteranimate', function() { this.fireEvent('keyframe', this, ++this.keyframeStep); }, this); } anims[ln - 1].on('afteranimate', function() { this.fireEvent('afteranimate', this, this.startTime, new Date() - this.startTime); }, this); Ext.defer(function(anim) { this.startAnimator(anim); }, this.delay, this, [anims[0]]); } }, /** * @private */ startAnimator: function(anim) { this.startTime = new Date(); anim.paused = false; } });keyframes : { '0%': { left: 100 }, '40%': { left: 150 }, '60%': { left: 75 }, '100%': { left: 100 } }