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