Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Anim.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-Anim'>/**
19 </span> * @class Ext.fx.Anim
20  *
21  * This class manages animation for a specific {@link #target}. The animation allows
22  * animation of various properties on the target, such as size, position, color and others.
23  *
24  * ## Starting Conditions
25  * The starting conditions for the animation are provided by the {@link #from} configuration.
26  * Any/all of the properties in the {@link #from} configuration can be specified. If a particular
27  * property is not defined, the starting value for that property will be read directly from the target.
28  *
29  * ## End Conditions
30  * The ending conditions for the animation are provided by the {@link #to} configuration. These mark
31  * the final values once the animations has finished. The values in the {@link #from} can mirror
32  * those in the {@link #to} configuration to provide a starting point.
33  *
34  * ## Other Options
35  *  - {@link #duration}: Specifies the time period of the animation.
36  *  - {@link #easing}: Specifies the easing of the animation.
37  *  - {@link #iterations}: Allows the animation to repeat a number of times.
38  *  - {@link #alternate}: Used in conjunction with {@link #iterations}, reverses the direction every second iteration.
39  *
40  * ## Example Code
41  *
42  *     @example
43  *     var myComponent = Ext.create('Ext.Component', {
44  *         renderTo: document.body,
45  *         width: 200,
46  *         height: 200,
47  *         style: 'border: 1px solid red;'
48  *     });
49  *
50  *     Ext.create('Ext.fx.Anim', {
51  *         target: myComponent,
52  *         duration: 1000,
53  *         from: {
54  *             width: 400 //starting width 400
55  *         },
56  *         to: {
57  *             width: 300, //end width 300
58  *             height: 300 // end width 300
59  *         }
60  *     });
61  */
62 Ext.define('Ext.fx.Anim', {
63
64     /* Begin Definitions */
65
66     mixins: {
67         observable: 'Ext.util.Observable'
68     },
69
70     requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'],
71
72     /* End Definitions */
73
74     isAnimation: true,
75
76 <span id='Ext-fx-Anim-cfg-callback'>    /**
77 </span>     * @cfg {Function} callback
78      * A function to be run after the animation has completed.
79      */
80
81 <span id='Ext-fx-Anim-cfg-scope'>    /**
82 </span>     * @cfg {Function} scope
83      * The scope that the {@link #callback} function will be called with
84      */
85
86 <span id='Ext-fx-Anim-cfg-duration'>    /**
87 </span>     * @cfg {Number} duration
88      * Time in milliseconds for a single animation to last. Defaults to 250. If the {@link #iterations} property is
89      * specified, then each animate will take the same duration for each iteration.
90      */
91     duration: 250,
92
93 <span id='Ext-fx-Anim-cfg-delay'>    /**
94 </span>     * @cfg {Number} delay
95      * Time to delay before starting the animation. Defaults to 0.
96      */
97     delay: 0,
98
99     /* private used to track a delayed starting time */
100     delayStart: 0,
101
102 <span id='Ext-fx-Anim-cfg-dynamic'>    /**
103 </span>     * @cfg {Boolean} dynamic
104      * 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.
105      */
106     dynamic: false,
107
108 <span id='Ext-fx-Anim-cfg-easing'>    /**
109 </span>     * @cfg {String} easing
110 This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
111 speed over its duration.
112
113          -backIn
114          -backOut
115          -bounceIn
116          -bounceOut
117          -ease
118          -easeIn
119          -easeOut
120          -easeInOut
121          -elasticIn
122          -elasticOut
123          -cubic-bezier(x1, y1, x2, y2)
124
125 Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
126 specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
127 be in the range [0, 1] or the definition is invalid.
128
129 [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
130
131      * @markdown
132      */
133     easing: 'ease',
134
135 <span id='Ext-fx-Anim-cfg-keyframes'>     /**
136 </span>      * @cfg {Object} keyframes
137       * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
138       * is considered '100%'.&lt;b&gt;Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
139       * &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
140       * animation.  The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
141       * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
142  &lt;pre&gt;&lt;code&gt;
143 keyframes : {
144     '0%': {
145         left: 100
146     },
147     '40%': {
148         left: 150
149     },
150     '60%': {
151         left: 75
152     },
153     '100%': {
154         left: 100
155     }
156 }
157  &lt;/code&gt;&lt;/pre&gt;
158       */
159
160 <span id='Ext-fx-Anim-property-damper'>    /**
161 </span>     * @private
162      */
163     damper: 1,
164
165 <span id='Ext-fx-Anim-property-bezierRE'>    /**
166 </span>     * @private
167      */
168     bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
169
170 <span id='Ext-fx-Anim-cfg-reverse'>    /**
171 </span>     * Run the animation from the end to the beginning
172      * Defaults to false.
173      * @cfg {Boolean} reverse
174      */
175     reverse: false,
176
177 <span id='Ext-fx-Anim-property-running'>    /**
178 </span>     * Flag to determine if the animation has started
179      * @property running
180      * @type Boolean
181      */
182     running: false,
183
184 <span id='Ext-fx-Anim-property-paused'>    /**
185 </span>     * Flag to determine if the animation is paused. Only set this to true if you need to
186      * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
187      * @property paused
188      * @type Boolean
189      */
190     paused: false,
191
192 <span id='Ext-fx-Anim-cfg-iterations'>    /**
193 </span>     * Number of times to execute the animation. Defaults to 1.
194      * @cfg {Number} iterations
195      */
196     iterations: 1,
197
198 <span id='Ext-fx-Anim-cfg-alternate'>    /**
199 </span>     * Used in conjunction with iterations to reverse the animation each time an iteration completes.
200      * @cfg {Boolean} alternate
201      * Defaults to false.
202      */
203     alternate: false,
204
205 <span id='Ext-fx-Anim-property-currentIteration'>    /**
206 </span>     * Current iteration the animation is running.
207      * @property currentIteration
208      * @type Number
209      */
210     currentIteration: 0,
211
212 <span id='Ext-fx-Anim-property-startTime'>    /**
213 </span>     * Starting time of the animation.
214      * @property startTime
215      * @type Date
216      */
217     startTime: 0,
218
219 <span id='Ext-fx-Anim-property-propHandlers'>    /**
220 </span>     * Contains a cache of the interpolators to be used.
221      * @private
222      * @property propHandlers
223      * @type Object
224      */
225
226 <span id='Ext-fx-Anim-cfg-target'>    /**
227 </span>     * @cfg {String/Object} target
228      * The {@link Ext.fx.target.Target} to apply the animation to.  This should only be specified when creating an Ext.fx.Anim directly.
229      * The target does not need to be a {@link Ext.fx.target.Target} instance, it can be the underlying object. For example, you can
230      * pass a Component, Element or Sprite as the target and the Anim will create the appropriate {@link Ext.fx.target.Target} object
231      * automatically.
232      */
233
234 <span id='Ext-fx-Anim-cfg-from'>    /**
235 </span>     * @cfg {Object} from
236      * An object containing property/value pairs for the beginning of the animation.  If not specified, the current state of the
237      * Ext.fx.target will be used. For example:
238 &lt;pre&gt;&lt;code&gt;
239 from : {
240     opacity: 0,       // Transparent
241     color: '#ffffff', // White
242     left: 0
243 }
244 &lt;/code&gt;&lt;/pre&gt;
245      */
246
247 <span id='Ext-fx-Anim-cfg-to'>    /**
248 </span>     * @cfg {Object} to
249      * An object containing property/value pairs for the end of the animation. For example:
250  &lt;pre&gt;&lt;code&gt;
251  to : {
252      opacity: 1,       // Opaque
253      color: '#00ff00', // Green
254      left: 500
255  }
256  &lt;/code&gt;&lt;/pre&gt;
257      */
258
259     // @private
260     constructor: function(config) {
261         var me = this,
262             curve;
263             
264         config = config || {};
265         // If keyframes are passed, they really want an Animator instead.
266         if (config.keyframes) {
267             return Ext.create('Ext.fx.Animator', config);
268         }
269         config = Ext.apply(me, config);
270         if (me.from === undefined) {
271             me.from = {};
272         }
273         me.propHandlers = {};
274         me.config = config;
275         me.target = Ext.fx.Manager.createTarget(me.target);
276         me.easingFn = Ext.fx.Easing[me.easing];
277         me.target.dynamic = me.dynamic;
278
279         // If not a pre-defined curve, try a cubic-bezier
280         if (!me.easingFn) {
281             me.easingFn = String(me.easing).match(me.bezierRE);
282             if (me.easingFn &amp;&amp; me.easingFn.length == 5) {
283                 curve = me.easingFn;
284                 me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
285             }
286         }
287         me.id = Ext.id(null, 'ext-anim-');
288         Ext.fx.Manager.addAnim(me);
289         me.addEvents(
290 <span id='Ext-fx-Anim-event-beforeanimate'>            /**
291 </span>             * @event beforeanimate
292              * Fires before the animation starts. A handler can return false to cancel the animation.
293              * @param {Ext.fx.Anim} this
294              */
295             'beforeanimate',
296 <span id='Ext-fx-Anim-event-afteranimate'>             /**
297 </span>              * @event afteranimate
298               * Fires when the animation is complete.
299               * @param {Ext.fx.Anim} this
300               * @param {Date} startTime
301               */
302             'afteranimate',
303 <span id='Ext-fx-Anim-event-lastframe'>             /**
304 </span>              * @event lastframe
305               * Fires when the animation's last frame has been set.
306               * @param {Ext.fx.Anim} this
307               * @param {Date} startTime
308               */
309             'lastframe'
310         );
311         me.mixins.observable.constructor.call(me, config);
312         if (config.callback) {
313             me.on('afteranimate', config.callback, config.scope);
314         }
315         return me;
316     },
317
318 <span id='Ext-fx-Anim-method-setAttr'>    /**
319 </span>     * @private
320      * Helper to the target
321      */
322     setAttr: function(attr, value) {
323         return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
324     },
325
326 <span id='Ext-fx-Anim-method-initAttrs'>    /**
327 </span>     * @private
328      * Set up the initial currentAttrs hash.
329      */
330     initAttrs: function() {
331         var me = this,
332             from = me.from,
333             to = me.to,
334             initialFrom = me.initialFrom || {},
335             out = {},
336             start, end, propHandler, attr;
337
338         for (attr in to) {
339             if (to.hasOwnProperty(attr)) {
340                 start = me.target.getAttr(attr, from[attr]);
341                 end = to[attr];
342                 // Use default (numeric) property handler
343                 if (!Ext.fx.PropertyHandler[attr]) {
344                     if (Ext.isObject(end)) {
345                         propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object;
346                     } else {
347                         propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler;
348                     }
349                 }
350                 // Use custom handler
351                 else {
352                     propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr];
353                 }
354                 out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr);
355             }
356         }
357         me.currentAttrs = out;
358     },
359
360 <span id='Ext-fx-Anim-method-start'>    /**
361 </span>     * @private
362      * Fires beforeanimate and sets the running flag.
363      */
364     start: function(startTime) {
365         var me = this,
366             delay = me.delay,
367             delayStart = me.delayStart,
368             delayDelta;
369         if (delay) {
370             if (!delayStart) {
371                 me.delayStart = startTime;
372                 return;
373             }
374             else {
375                 delayDelta = startTime - delayStart;
376                 if (delayDelta &lt; delay) {
377                     return;
378                 }
379                 else {
380                     // Compensate for frame delay;
381                     startTime = new Date(delayStart.getTime() + delay);
382                 }
383             }
384         }
385         if (me.fireEvent('beforeanimate', me) !== false) {
386             me.startTime = startTime;
387             if (!me.paused &amp;&amp; !me.currentAttrs) {
388                 me.initAttrs();
389             }
390             me.running = true;
391         }
392     },
393
394 <span id='Ext-fx-Anim-method-runAnim'>    /**
395 </span>     * @private
396      * Calculate attribute value at the passed timestamp.
397      * @returns a hash of the new attributes.
398      */
399     runAnim: function(elapsedTime) {
400         var me = this,
401             attrs = me.currentAttrs,
402             duration = me.duration,
403             easingFn = me.easingFn,
404             propHandlers = me.propHandlers,
405             ret = {},
406             easing, values, attr, lastFrame;
407
408         if (elapsedTime &gt;= duration) {
409             elapsedTime = duration;
410             lastFrame = true;
411         }
412         if (me.reverse) {
413             elapsedTime = duration - elapsedTime;
414         }
415
416         for (attr in attrs) {
417             if (attrs.hasOwnProperty(attr)) {
418                 values = attrs[attr];
419                 easing = lastFrame ? 1 : easingFn(elapsedTime / duration);
420                 ret[attr] = propHandlers[attr].set(values, easing);
421             }
422         }
423         return ret;
424     },
425
426 <span id='Ext-fx-Anim-method-lastFrame'>    /**
427 </span>     * @private
428      * Perform lastFrame cleanup and handle iterations
429      * @returns a hash of the new attributes.
430      */
431     lastFrame: function() {
432         var me = this,
433             iter = me.iterations,
434             iterCount = me.currentIteration;
435
436         iterCount++;
437         if (iterCount &lt; iter) {
438             if (me.alternate) {
439                 me.reverse = !me.reverse;
440             }
441             me.startTime = new Date();
442             me.currentIteration = iterCount;
443             // Turn off paused for CSS3 Transitions
444             me.paused = false;
445         }
446         else {
447             me.currentIteration = 0;
448             me.end();
449             me.fireEvent('lastframe', me, me.startTime);
450         }
451     },
452
453 <span id='Ext-fx-Anim-method-end'>    /**
454 </span>     * Fire afteranimate event and end the animation. Usually called automatically when the
455      * animation reaches its final frame, but can also be called manually to pre-emptively
456      * stop and destroy the running animation.
457      */
458     end: function() {
459         var me = this;
460         me.startTime = 0;
461         me.paused = false;
462         me.running = false;
463         Ext.fx.Manager.removeAnim(me);
464         me.fireEvent('afteranimate', me, me.startTime);
465     }
466 });
467 // Set flag to indicate that Fx is available. Class might not be available immediately.
468 Ext.enableFx = true;
469 </pre>
470 </body>
471 </html>