| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-fx-Animator'>/**</span> * @class Ext.fx.Animator * * This class is used to run keyframe based animations, which follows the CSS3 based animation structure. * Keyframe animations differ from typical from/to animations in that they offer the ability to specify values * at various points throughout the animation. * * ## Using Keyframes * * The {@link #keyframes} option is the most important part of specifying an animation when using this * class. A key frame is a point in a particular animation. We represent this as a percentage of the * total animation duration. At each key frame, we can specify the target values at that time. Note that * you *must* specify the values at 0% and 100%, the start and ending values. There is also a {@link #keyframe} * event that fires after each key frame is reached. * * ## Example * * In the example below, we modify the values of the element at each fifth throughout the animation. * *     @example *     Ext.create('Ext.fx.Animator', { *         target: Ext.getBody().createChild({ *             style: { *                 width: '100px', *                 height: '100px', *                 'background-color': 'red' *             } *         }), *         duration: 10000, // 10 seconds *         keyframes: { *             0: { *                 opacity: 1, *                 backgroundColor: 'FF0000' *             }, *             20: { *                 x: 30, *                 opacity: 0.5 *             }, *             40: { *                 x: 130, *                 backgroundColor: '0000FF' *             }, *             60: { *                 y: 80, *                 opacity: 0.3 *             }, *             80: { *                 width: 200, *                 y: 200 *             }, *             100: { *                 opacity: 1, *                 backgroundColor: '00FF00' *             } *         } *     }); */Ext.define('Ext.fx.Animator', {    /* Begin Definitions */    mixins: {        observable: 'Ext.util.Observable'    },    requires: ['Ext.fx.Manager'],    /* End Definitions */<span id='Ext-fx-Animator-property-isAnimator'>    /**</span>     * @property {Boolean} isAnimator     * `true` in this class to identify an object as an instantiated Animator, or subclass thereof.     */    isAnimator: true,<span id='Ext-fx-Animator-cfg-duration'>    /**</span>     * @cfg {Number} duration     * Time in milliseconds for the animation to last. Defaults to 250.     */    duration: 250,<span id='Ext-fx-Animator-cfg-delay'>    /**</span>     * @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,<span id='Ext-fx-Animator-cfg-dynamic'>    /**</span>     * @cfg {Boolean} dynamic     * Currently only for Component Animation: Only set a component's outer element size bypassing layouts.  Set to true to do full layouts for every frame of the animation.  Defaults to false.     */    dynamic: false,<span id='Ext-fx-Animator-cfg-easing'>    /**</span>     * @cfg {String} easing     *     * This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change     * speed over its duration.     *     *  - backIn     *  - backOut     *  - bounceIn     *  - bounceOut     *  - ease     *  - easeIn     *  - easeOut     *  - easeInOut     *  - elasticIn     *  - elasticOut     *  - cubic-bezier(x1, y1, x2, y2)     *     * Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]     * specification.  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.     *     * [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag     */    easing: 'ease',<span id='Ext-fx-Animator-property-running'>    /**</span>     * Flag to determine if the animation has started     * @property running     * @type Boolean     */    running: false,<span id='Ext-fx-Animator-property-paused'>    /**</span>     * 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,<span id='Ext-fx-Animator-property-damper'>    /**</span>     * @private     */    damper: 1,<span id='Ext-fx-Animator-cfg-iterations'>    /**</span>     * @cfg {Number} iterations     * Number of times to execute the animation. Defaults to 1.     */    iterations: 1,<span id='Ext-fx-Animator-property-currentIteration'>    /**</span>     * Current iteration the animation is running.     * @property currentIteration     * @type Number     */    currentIteration: 0,<span id='Ext-fx-Animator-property-keyframeStep'>    /**</span>     * Current keyframe step of the animation.     * @property keyframeStep     * @type Number     */    keyframeStep: 0,<span id='Ext-fx-Animator-property-animKeyFramesRE'>    /**</span>     * @private     */    animKeyFramesRE: /^(from|to|\d+%?)$/,<span id='Ext-fx-Animator-cfg-target'>    /**</span>     * @cfg {Ext.fx.target.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.     */<span id='Ext-fx-Animator-cfg-keyframes'>     /**</span>      * @cfg {Object} keyframes      * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'      * is considered '100%'.<b>Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using      * "from" or "to"</b>.  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: <pre><code>keyframes : {    '0%': {        left: 100    },    '40%': {        left: 150    },    '60%': {        left: 75    },    '100%': {        left: 100    }} </code></pre>      */    constructor: function(config) {        var me = this;        config = Ext.apply(me, config || {});        me.config = config;        me.id = Ext.id(null, 'ext-animator-');        me.addEvents(<span id='Ext-fx-Animator-event-beforeanimate'>            /**</span>             * @event beforeanimate             * Fires before the animation starts. A handler can return false to cancel the animation.             * @param {Ext.fx.Animator} this             */            'beforeanimate',<span id='Ext-fx-Animator-event-keyframe'>            /**</span>              * @event keyframe              * Fires at each keyframe.              * @param {Ext.fx.Animator} this              * @param {Number} keyframe step number              */            'keyframe',<span id='Ext-fx-Animator-event-afteranimate'>            /**</span>             * @event afteranimate             * Fires when the animation is complete.             * @param {Ext.fx.Animator} this             * @param {Date} startTime             */            'afteranimate'        );        me.mixins.observable.constructor.call(me, config);        me.timeline = [];        me.createTimeline(me.keyframes);        if (me.target) {            me.applyAnimator(me.target);            Ext.fx.Manager.addAnim(me);        }    },<span id='Ext-fx-Animator-method-sorter'>    /**</span>     * @private     */    sorter: function (a, b) {        return a.pct - b.pct;    },<span id='Ext-fx-Animator-method-createTimeline'>    /**</span>     * @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 me = this,            attrs = [],            to = me.to || {},            duration = me.duration,            prevMs, ms, i, ln, pct, anim, nextAnim, attr;        for (pct in keyframes) {            if (keyframes.hasOwnProperty(pct) && me.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        Ext.Array.sort(attrs, me.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);            me.timeline.push({                duration: ms - prevMs,                attrs: attrs[i].attrs            });        }    },<span id='Ext-fx-Animator-property-applyAnimator'>    /**</span>     * Applies animation to the Ext.fx.target     * @private     * @param target     * @type String/Object     */    applyAnimator: function(target) {        var me = this,            anims = [],            timeline = me.timeline,            reverse = me.reverse,            ln = timeline.length,            anim, easing, damper, initial, attrs, lastAttrs, i;        if (me.fireEvent('beforeanimate', me) !== false) {            for (i = 0; i < ln; i++) {                anim = timeline[i];                attrs = anim.attrs;                easing = attrs.easing || me.easing;                damper = attrs.damper || me.damper;                delete attrs.easing;                delete attrs.damper;                anim = new Ext.fx.Anim({                    target: target,                    easing: easing,                    damper: damper,                    duration: anim.duration,                    paused: true,                    to: attrs                });                anims.push(anim);            }            me.animations = anims;            me.target = anim.target;            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);                }, me);            }            anims[ln - 1].on('afteranimate', function() {                this.lastFrame();            }, me);        }    },<span id='Ext-fx-Animator-method-start'>    /**</span>     * @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.running = true;            me.animations[me.keyframeStep].paused = false;        }    },<span id='Ext-fx-Animator-method-lastFrame'>    /**</span>     * @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) {            me.startTime = new Date();            me.currentIteration = iterCount;            me.keyframeStep = 0;            me.applyAnimator(me.target);            me.animations[me.keyframeStep].paused = false;        }        else {            me.currentIteration = 0;            me.end();        }    },<span id='Ext-fx-Animator-method-end'>    /**</span>     * 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, new Date() - me.startTime);    },        isReady: function() {        return this.paused === false && this.running === false && this.iterations > 0;    },        isRunning: function() {        // Explicitly return false, we don't want to be run continuously by the manager        return false;    }});</pre></body></html>
 |