Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Animator.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-fx-Animator'>/**
19 </span> * @class Ext.fx.Animator
20  *
21  * This class is used to run keyframe based animations, which follows the CSS3 based animation structure.
22  * Keyframe animations differ from typical from/to animations in that they offer the ability to specify values
23  * at various points throughout the animation.
24  *
25  * ## Using Keyframes
26  *
27  * The {@link #keyframes} option is the most important part of specifying an animation when using this
28  * class. A key frame is a point in a particular animation. We represent this as a percentage of the
29  * total animation duration. At each key frame, we can specify the target values at that time. Note that
30  * you *must* specify the values at 0% and 100%, the start and ending values. There is also a {@link #keyframe}
31  * event that fires after each key frame is reached.
32  *
33  * ## Example
34  *
35  * In the example below, we modify the values of the element at each fifth throughout the animation.
36  *
37  *     @example
38  *     Ext.create('Ext.fx.Animator', {
39  *         target: Ext.getBody().createChild({
40  *             style: {
41  *                 width: '100px',
42  *                 height: '100px',
43  *                 'background-color': 'red'
44  *             }
45  *         }),
46  *         duration: 10000, // 10 seconds
47  *         keyframes: {
48  *             0: {
49  *                 opacity: 1,
50  *                 backgroundColor: 'FF0000'
51  *             },
52  *             20: {
53  *                 x: 30,
54  *                 opacity: 0.5
55  *             },
56  *             40: {
57  *                 x: 130,
58  *                 backgroundColor: '0000FF'
59  *             },
60  *             60: {
61  *                 y: 80,
62  *                 opacity: 0.3
63  *             },
64  *             80: {
65  *                 width: 200,
66  *                 y: 200
67  *             },
68  *             100: {
69  *                 opacity: 1,
70  *                 backgroundColor: '00FF00'
71  *             }
72  *         }
73  *     });
74  */
75 Ext.define('Ext.fx.Animator', {
76
77     /* Begin Definitions */
78
79     mixins: {
80         observable: 'Ext.util.Observable'
81     },
82
83     requires: ['Ext.fx.Manager'],
84
85     /* End Definitions */
86
87     isAnimator: true,
88
89 <span id='Ext-fx-Animator-cfg-duration'>    /**
90 </span>     * @cfg {Number} duration
91      * Time in milliseconds for the animation to last. Defaults to 250.
92      */
93     duration: 250,
94
95 <span id='Ext-fx-Animator-cfg-delay'>    /**
96 </span>     * @cfg {Number} delay
97      * Time to delay before starting the animation. Defaults to 0.
98      */
99     delay: 0,
100
101     /* private used to track a delayed starting time */
102     delayStart: 0,
103
104 <span id='Ext-fx-Animator-cfg-dynamic'>    /**
105 </span>     * @cfg {Boolean} dynamic
106      * 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.
107      */
108     dynamic: false,
109
110 <span id='Ext-fx-Animator-cfg-easing'>    /**
111 </span>     * @cfg {String} easing
112      *
113      * This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
114      * speed over its duration.
115      *
116      *  - backIn
117      *  - backOut
118      *  - bounceIn
119      *  - bounceOut
120      *  - ease
121      *  - easeIn
122      *  - easeOut
123      *  - easeInOut
124      *  - elasticIn
125      *  - elasticOut
126      *  - cubic-bezier(x1, y1, x2, y2)
127      *
128      * Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
129      * specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
130      * be in the range [0, 1] or the definition is invalid.
131      *
132      * [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
133      */
134     easing: 'ease',
135
136 <span id='Ext-fx-Animator-property-running'>    /**
137 </span>     * Flag to determine if the animation has started
138      * @property running
139      * @type Boolean
140      */
141     running: false,
142
143 <span id='Ext-fx-Animator-property-paused'>    /**
144 </span>     * Flag to determine if the animation is paused. Only set this to true if you need to
145      * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
146      * @property paused
147      * @type Boolean
148      */
149     paused: false,
150
151 <span id='Ext-fx-Animator-property-damper'>    /**
152 </span>     * @private
153      */
154     damper: 1,
155
156 <span id='Ext-fx-Animator-cfg-iterations'>    /**
157 </span>     * @cfg {Number} iterations
158      * Number of times to execute the animation. Defaults to 1.
159      */
160     iterations: 1,
161
162 <span id='Ext-fx-Animator-property-currentIteration'>    /**
163 </span>     * Current iteration the animation is running.
164      * @property currentIteration
165      * @type Number
166      */
167     currentIteration: 0,
168
169 <span id='Ext-fx-Animator-property-keyframeStep'>    /**
170 </span>     * Current keyframe step of the animation.
171      * @property keyframeStep
172      * @type Number
173      */
174     keyframeStep: 0,
175
176 <span id='Ext-fx-Animator-property-animKeyFramesRE'>    /**
177 </span>     * @private
178      */
179     animKeyFramesRE: /^(from|to|\d+%?)$/,
180
181 <span id='Ext-fx-Animator-cfg-target'>    /**
182 </span>     * @cfg {Ext.fx.target.Target} target
183      * The Ext.fx.target to apply the animation to.  If not specified during initialization, this can be passed to the applyAnimator
184      * method to apply the same animation to many targets.
185      */
186
187 <span id='Ext-fx-Animator-cfg-keyframes'>     /**
188 </span>      * @cfg {Object} keyframes
189       * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
190       * is considered '100%'.&lt;b&gt;Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
191       * &quot;from&quot; or &quot;to&quot;&lt;/b&gt;.  A keyframe declaration without these keyframe selectors is invalid and will not be available for
192       * animation.  The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
193       * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
194  &lt;pre&gt;&lt;code&gt;
195 keyframes : {
196     '0%': {
197         left: 100
198     },
199     '40%': {
200         left: 150
201     },
202     '60%': {
203         left: 75
204     },
205     '100%': {
206         left: 100
207     }
208 }
209  &lt;/code&gt;&lt;/pre&gt;
210       */
211     constructor: function(config) {
212         var me = this;
213         config = Ext.apply(me, config || {});
214         me.config = config;
215         me.id = Ext.id(null, 'ext-animator-');
216         me.addEvents(
217 <span id='Ext-fx-Animator-event-beforeanimate'>            /**
218 </span>             * @event beforeanimate
219              * Fires before the animation starts. A handler can return false to cancel the animation.
220              * @param {Ext.fx.Animator} this
221              */
222             'beforeanimate',
223 <span id='Ext-fx-Animator-event-keyframe'>            /**
224 </span>              * @event keyframe
225               * Fires at each keyframe.
226               * @param {Ext.fx.Animator} this
227               * @param {Number} keyframe step number
228               */
229             'keyframe',
230 <span id='Ext-fx-Animator-event-afteranimate'>            /**
231 </span>             * @event afteranimate
232              * Fires when the animation is complete.
233              * @param {Ext.fx.Animator} this
234              * @param {Date} startTime
235              */
236             'afteranimate'
237         );
238         me.mixins.observable.constructor.call(me, config);
239         me.timeline = [];
240         me.createTimeline(me.keyframes);
241         if (me.target) {
242             me.applyAnimator(me.target);
243             Ext.fx.Manager.addAnim(me);
244         }
245     },
246
247 <span id='Ext-fx-Animator-method-sorter'>    /**
248 </span>     * @private
249      */
250     sorter: function (a, b) {
251         return a.pct - b.pct;
252     },
253
254 <span id='Ext-fx-Animator-method-createTimeline'>    /**
255 </span>     * @private
256      * Takes the given keyframe configuration object and converts it into an ordered array with the passed attributes per keyframe
257      * or applying the 'to' configuration to all keyframes.  Also calculates the proper animation duration per keyframe.
258      */
259     createTimeline: function(keyframes) {
260         var me = this,
261             attrs = [],
262             to = me.to || {},
263             duration = me.duration,
264             prevMs, ms, i, ln, pct, anim, nextAnim, attr;
265
266         for (pct in keyframes) {
267             if (keyframes.hasOwnProperty(pct) &amp;&amp; me.animKeyFramesRE.test(pct)) {
268                 attr = {attrs: Ext.apply(keyframes[pct], to)};
269                 // CSS3 spec allow for from/to to be specified.
270                 if (pct == &quot;from&quot;) {
271                     pct = 0;
272                 }
273                 else if (pct == &quot;to&quot;) {
274                     pct = 100;
275                 }
276                 // convert % values into integers
277                 attr.pct = parseInt(pct, 10);
278                 attrs.push(attr);
279             }
280         }
281         // Sort by pct property
282         Ext.Array.sort(attrs, me.sorter);
283         // Only an end
284         //if (attrs[0].pct) {
285         //    attrs.unshift({pct: 0, attrs: element.attrs});
286         //}
287
288         ln = attrs.length;
289         for (i = 0; i &lt; ln; i++) {
290             prevMs = (attrs[i - 1]) ? duration * (attrs[i - 1].pct / 100) : 0;
291             ms = duration * (attrs[i].pct / 100);
292             me.timeline.push({
293                 duration: ms - prevMs,
294                 attrs: attrs[i].attrs
295             });
296         }
297     },
298
299 <span id='Ext-fx-Animator-property-applyAnimator'>    /**
300 </span>     * Applies animation to the Ext.fx.target
301      * @private
302      * @param target
303      * @type String/Object
304      */
305     applyAnimator: function(target) {
306         var me = this,
307             anims = [],
308             timeline = me.timeline,
309             reverse = me.reverse,
310             ln = timeline.length,
311             anim, easing, damper, initial, attrs, lastAttrs, i;
312
313         if (me.fireEvent('beforeanimate', me) !== false) {
314             for (i = 0; i &lt; ln; i++) {
315                 anim = timeline[i];
316                 attrs = anim.attrs;
317                 easing = attrs.easing || me.easing;
318                 damper = attrs.damper || me.damper;
319                 delete attrs.easing;
320                 delete attrs.damper;
321                 anim = Ext.create('Ext.fx.Anim', {
322                     target: target,
323                     easing: easing,
324                     damper: damper,
325                     duration: anim.duration,
326                     paused: true,
327                     to: attrs
328                 });
329                 anims.push(anim);
330             }
331             me.animations = anims;
332             me.target = anim.target;
333             for (i = 0; i &lt; ln - 1; i++) {
334                 anim = anims[i];
335                 anim.nextAnim = anims[i + 1];
336                 anim.on('afteranimate', function() {
337                     this.nextAnim.paused = false;
338                 });
339                 anim.on('afteranimate', function() {
340                     this.fireEvent('keyframe', this, ++this.keyframeStep);
341                 }, me);
342             }
343             anims[ln - 1].on('afteranimate', function() {
344                 this.lastFrame();
345             }, me);
346         }
347     },
348
349 <span id='Ext-fx-Animator-method-start'>    /**
350 </span>     * @private
351      * Fires beforeanimate and sets the running flag.
352      */
353     start: function(startTime) {
354         var me = this,
355             delay = me.delay,
356             delayStart = me.delayStart,
357             delayDelta;
358         if (delay) {
359             if (!delayStart) {
360                 me.delayStart = startTime;
361                 return;
362             }
363             else {
364                 delayDelta = startTime - delayStart;
365                 if (delayDelta &lt; delay) {
366                     return;
367                 }
368                 else {
369                     // Compensate for frame delay;
370                     startTime = new Date(delayStart.getTime() + delay);
371                 }
372             }
373         }
374         if (me.fireEvent('beforeanimate', me) !== false) {
375             me.startTime = startTime;
376             me.running = true;
377             me.animations[me.keyframeStep].paused = false;
378         }
379     },
380
381 <span id='Ext-fx-Animator-method-lastFrame'>    /**
382 </span>     * @private
383      * Perform lastFrame cleanup and handle iterations
384      * @returns a hash of the new attributes.
385      */
386     lastFrame: function() {
387         var me = this,
388             iter = me.iterations,
389             iterCount = me.currentIteration;
390
391         iterCount++;
392         if (iterCount &lt; iter) {
393             me.startTime = new Date();
394             me.currentIteration = iterCount;
395             me.keyframeStep = 0;
396             me.applyAnimator(me.target);
397             me.animations[me.keyframeStep].paused = false;
398         }
399         else {
400             me.currentIteration = 0;
401             me.end();
402         }
403     },
404
405 <span id='Ext-fx-Animator-method-end'>    /**
406 </span>     * Fire afteranimate event and end the animation. Usually called automatically when the
407      * animation reaches its final frame, but can also be called manually to pre-emptively
408      * stop and destroy the running animation.
409      */
410     end: function() {
411         var me = this;
412         me.fireEvent('afteranimate', me, me.startTime, new Date() - me.startTime);
413     }
414 });</pre>
415 </body>
416 </html>