3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
18 * This class manages animation for a specific {@link #target}. The animation allows
19 * animation of various properties on the target, such as size, position, color and others.
21 * ## Starting Conditions
22 * The starting conditions for the animation are provided by the {@link #from} configuration.
23 * Any/all of the properties in the {@link #from} configuration can be specified. If a particular
24 * property is not defined, the starting value for that property will be read directly from the target.
27 * The ending conditions for the animation are provided by the {@link #to} configuration. These mark
28 * the final values once the animations has finished. The values in the {@link #from} can mirror
29 * those in the {@link #to} configuration to provide a starting point.
32 * - {@link #duration}: Specifies the time period of the animation.
33 * - {@link #easing}: Specifies the easing of the animation.
34 * - {@link #iterations}: Allows the animation to repeat a number of times.
35 * - {@link #alternate}: Used in conjunction with {@link #iterations}, reverses the direction every second iteration.
40 * var myComponent = Ext.create('Ext.Component', {
41 * renderTo: document.body,
44 * style: 'border: 1px solid red;'
47 * Ext.create('Ext.fx.Anim', {
48 * target: myComponent,
51 * width: 400 //starting width 400
54 * width: 300, //end width 300
55 * height: 300 // end width 300
59 Ext.define('Ext.fx.Anim', {
61 /* Begin Definitions */
64 observable: 'Ext.util.Observable'
67 requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'],
74 * @cfg {Function} callback
75 * A function to be run after the animation has completed.
79 * @cfg {Function} scope
80 * The scope that the {@link #callback} function will be called with
84 * @cfg {Number} duration
85 * Time in milliseconds for a single animation to last. Defaults to 250. If the {@link #iterations} property is
86 * specified, then each animate will take the same duration for each iteration.
92 * Time to delay before starting the animation. Defaults to 0.
96 /* private used to track a delayed starting time */
100 * @cfg {Boolean} dynamic
101 * 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.
106 * @cfg {String} easing
107 This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
108 speed over its duration.
120 -cubic-bezier(x1, y1, x2, y2)
122 Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
123 specification. The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
124 be in the range [0, 1] or the definition is invalid.
126 [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
133 * @cfg {Object} keyframes
134 * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
135 * is considered '100%'.<b>Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
136 * "from" or "to"</b>. A keyframe declaration without these keyframe selectors is invalid and will not be available for
137 * animation. The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
138 * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
165 bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
168 * Run the animation from the end to the beginning
170 * @cfg {Boolean} reverse
175 * Flag to determine if the animation has started
182 * Flag to determine if the animation is paused. Only set this to true if you need to
183 * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
190 * Number of times to execute the animation. Defaults to 1.
191 * @cfg {Number} iterations
196 * Used in conjunction with iterations to reverse the animation each time an iteration completes.
197 * @cfg {Boolean} alternate
203 * Current iteration the animation is running.
204 * @property currentIteration
210 * Starting time of the animation.
211 * @property startTime
217 * Contains a cache of the interpolators to be used.
219 * @property propHandlers
224 * @cfg {String/Object} target
225 * The {@link Ext.fx.target.Target} to apply the animation to. This should only be specified when creating an Ext.fx.Anim directly.
226 * The target does not need to be a {@link Ext.fx.target.Target} instance, it can be the underlying object. For example, you can
227 * pass a Component, Element or Sprite as the target and the Anim will create the appropriate {@link Ext.fx.target.Target} object
233 * An object containing property/value pairs for the beginning of the animation. If not specified, the current state of the
234 * Ext.fx.target will be used. For example:
237 opacity: 0, // Transparent
238 color: '#ffffff', // White
246 * An object containing property/value pairs for the end of the animation. For example:
249 opacity: 1, // Opaque
250 color: '#00ff00', // Green
257 constructor: function(config) {
261 config = config || {};
262 // If keyframes are passed, they really want an Animator instead.
263 if (config.keyframes) {
264 return Ext.create('Ext.fx.Animator', config);
266 config = Ext.apply(me, config);
267 if (me.from === undefined) {
270 me.propHandlers = {};
272 me.target = Ext.fx.Manager.createTarget(me.target);
273 me.easingFn = Ext.fx.Easing[me.easing];
274 me.target.dynamic = me.dynamic;
276 // If not a pre-defined curve, try a cubic-bezier
278 me.easingFn = String(me.easing).match(me.bezierRE);
279 if (me.easingFn && me.easingFn.length == 5) {
281 me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
284 me.id = Ext.id(null, 'ext-anim-');
285 Ext.fx.Manager.addAnim(me);
288 * @event beforeanimate
289 * Fires before the animation starts. A handler can return false to cancel the animation.
290 * @param {Ext.fx.Anim} this
294 * @event afteranimate
295 * Fires when the animation is complete.
296 * @param {Ext.fx.Anim} this
297 * @param {Date} startTime
302 * Fires when the animation's last frame has been set.
303 * @param {Ext.fx.Anim} this
304 * @param {Date} startTime
308 me.mixins.observable.constructor.call(me, config);
309 if (config.callback) {
310 me.on('afteranimate', config.callback, config.scope);
317 * Helper to the target
319 setAttr: function(attr, value) {
320 return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
325 * Set up the initial currentAttrs hash.
327 initAttrs: function() {
331 initialFrom = me.initialFrom || {},
333 start, end, propHandler, attr;
336 if (to.hasOwnProperty(attr)) {
337 start = me.target.getAttr(attr, from[attr]);
339 // Use default (numeric) property handler
340 if (!Ext.fx.PropertyHandler[attr]) {
341 if (Ext.isObject(end)) {
342 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object;
344 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler;
347 // Use custom handler
349 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr];
351 out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr);
354 me.currentAttrs = out;
359 * Fires beforeanimate and sets the running flag.
361 start: function(startTime) {
364 delayStart = me.delayStart,
368 me.delayStart = startTime;
372 delayDelta = startTime - delayStart;
373 if (delayDelta < delay) {
377 // Compensate for frame delay;
378 startTime = new Date(delayStart.getTime() + delay);
382 if (me.fireEvent('beforeanimate', me) !== false) {
383 me.startTime = startTime;
384 if (!me.paused && !me.currentAttrs) {
393 * Calculate attribute value at the passed timestamp.
394 * @returns a hash of the new attributes.
396 runAnim: function(elapsedTime) {
398 attrs = me.currentAttrs,
399 duration = me.duration,
400 easingFn = me.easingFn,
401 propHandlers = me.propHandlers,
403 easing, values, attr, lastFrame;
405 if (elapsedTime >= duration) {
406 elapsedTime = duration;
410 elapsedTime = duration - elapsedTime;
413 for (attr in attrs) {
414 if (attrs.hasOwnProperty(attr)) {
415 values = attrs[attr];
416 easing = lastFrame ? 1 : easingFn(elapsedTime / duration);
417 ret[attr] = propHandlers[attr].set(values, easing);
425 * Perform lastFrame cleanup and handle iterations
426 * @returns a hash of the new attributes.
428 lastFrame: function() {
430 iter = me.iterations,
431 iterCount = me.currentIteration;
434 if (iterCount < iter) {
436 me.reverse = !me.reverse;
438 me.startTime = new Date();
439 me.currentIteration = iterCount;
440 // Turn off paused for CSS3 Transitions
444 me.currentIteration = 0;
446 me.fireEvent('lastframe', me, me.startTime);
451 * Fire afteranimate event and end the animation. Usually called automatically when the
452 * animation reaches its final frame, but can also be called manually to pre-emptively
453 * stop and destroy the running animation.
460 Ext.fx.Manager.removeAnim(me);
461 me.fireEvent('afteranimate', me, me.startTime);
464 // Set flag to indicate that Fx is available. Class might not be available immediately.