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.
39 * var myComponent = Ext.create('Ext.Component', {
40 * renderTo: document.body,
43 * style: 'border: 1px solid red;'
47 * target: myComponent,
50 * width: 400 //starting width 400
53 * width: 300, //end width 300
54 * height: 300 // end width 300
58 Ext.define('Ext.fx.Anim', {
60 /* Begin Definitions */
63 observable: 'Ext.util.Observable'
66 requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'],
72 * @cfg {Number} duration
73 * Time in milliseconds for a single animation to last. Defaults to 250. If the {@link #iterations} property is
74 * specified, then each animate will take the same duration for each iteration.
80 * Time to delay before starting the animation. Defaults to 0.
84 /* private used to track a delayed starting time */
88 * @cfg {Boolean} dynamic
89 * 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.
94 * @cfg {String} easing
95 This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
96 speed over its duration.
108 -cubic-bezier(x1, y1, x2, y2)
110 Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
111 specification. The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
112 be in the range [0, 1] or the definition is invalid.
114 [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
121 * @cfg {Object} keyframes
122 * Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to'
123 * is considered '100%'.<b>Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using
124 * "from" or "to"</b>. A keyframe declaration without these keyframe selectors is invalid and will not be available for
125 * animation. The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to
126 * be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example:
153 bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,
156 * Run the animation from the end to the beginning
158 * @cfg {Boolean} reverse
163 * Flag to determine if the animation has started
170 * Flag to determine if the animation is paused. Only set this to true if you need to
171 * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
178 * Number of times to execute the animation. Defaults to 1.
179 * @cfg {int} iterations
184 * Used in conjunction with iterations to reverse the animation each time an iteration completes.
185 * @cfg {Boolean} alternate
191 * Current iteration the animation is running.
192 * @property currentIteration
198 * Starting time of the animation.
199 * @property startTime
205 * Contains a cache of the interpolators to be used.
207 * @property propHandlers
212 * @cfg {String/Object} target
213 * The {@link Ext.fx.target.Target} to apply the animation to. This should only be specified when creating an Ext.fx.Anim directly.
214 * The target does not need to be a {@link Ext.fx.target.Target} instance, it can be the underlying object. For example, you can
215 * pass a Component, Element or Sprite as the target and the Anim will create the appropriate {@link Ext.fx.target.Target} object
221 * An object containing property/value pairs for the beginning of the animation. If not specified, the current state of the
222 * Ext.fx.target will be used. For example:
225 opacity: 0, // Transparent
226 color: '#ffffff', // White
234 * An object containing property/value pairs for the end of the animation. For example:
237 opacity: 1, // Opaque
238 color: '#00ff00', // Green
245 constructor: function(config) {
247 config = config || {};
248 // If keyframes are passed, they really want an Animator instead.
249 if (config.keyframes) {
250 return Ext.create('Ext.fx.Animator', config);
252 config = Ext.apply(me, config);
253 if (me.from === undefined) {
256 me.propHandlers = {};
258 me.target = Ext.fx.Manager.createTarget(me.target);
259 me.easingFn = Ext.fx.Easing[me.easing];
260 me.target.dynamic = me.dynamic;
262 // If not a pre-defined curve, try a cubic-bezier
264 me.easingFn = String(me.easing).match(me.bezierRE);
265 if (me.easingFn && me.easingFn.length == 5) {
266 var curve = me.easingFn;
267 me.easingFn = Ext.fx.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
270 me.id = Ext.id(null, 'ext-anim-');
271 Ext.fx.Manager.addAnim(me);
274 * @event beforeanimate
275 * Fires before the animation starts. A handler can return false to cancel the animation.
276 * @param {Ext.fx.Anim} this
280 * @event afteranimate
281 * Fires when the animation is complete.
282 * @param {Ext.fx.Anim} this
283 * @param {Date} startTime
288 * Fires when the animation's last frame has been set.
289 * @param {Ext.fx.Anim} this
290 * @param {Date} startTime
294 me.mixins.observable.constructor.call(me, config);
295 if (config.callback) {
296 me.on('afteranimate', config.callback, config.scope);
303 * Helper to the target
305 setAttr: function(attr, value) {
306 return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
311 * Set up the initial currentAttrs hash.
313 initAttrs: function() {
317 initialFrom = me.initialFrom || {},
319 start, end, propHandler, attr;
322 if (to.hasOwnProperty(attr)) {
323 start = me.target.getAttr(attr, from[attr]);
325 // Use default (numeric) property handler
326 if (!Ext.fx.PropertyHandler[attr]) {
327 if (Ext.isObject(end)) {
328 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object;
330 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler;
333 // Use custom handler
335 propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr];
337 out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr);
340 me.currentAttrs = out;
345 * Fires beforeanimate and sets the running flag.
347 start: function(startTime) {
350 delayStart = me.delayStart,
354 me.delayStart = startTime;
358 delayDelta = startTime - delayStart;
359 if (delayDelta < delay) {
363 // Compensate for frame delay;
364 startTime = new Date(delayStart.getTime() + delay);
368 if (me.fireEvent('beforeanimate', me) !== false) {
369 me.startTime = startTime;
370 if (!me.paused && !me.currentAttrs) {
379 * Calculate attribute value at the passed timestamp.
380 * @returns a hash of the new attributes.
382 runAnim: function(elapsedTime) {
384 attrs = me.currentAttrs,
385 duration = me.duration,
386 easingFn = me.easingFn,
387 propHandlers = me.propHandlers,
389 easing, values, attr, lastFrame;
391 if (elapsedTime >= duration) {
392 elapsedTime = duration;
396 elapsedTime = duration - elapsedTime;
399 for (attr in attrs) {
400 if (attrs.hasOwnProperty(attr)) {
401 values = attrs[attr];
402 easing = lastFrame ? 1 : easingFn(elapsedTime / duration);
403 ret[attr] = propHandlers[attr].set(values, easing);
411 * Perform lastFrame cleanup and handle iterations
412 * @returns a hash of the new attributes.
414 lastFrame: function() {
416 iter = me.iterations,
417 iterCount = me.currentIteration;
420 if (iterCount < iter) {
422 me.reverse = !me.reverse;
424 me.startTime = new Date();
425 me.currentIteration = iterCount;
426 // Turn off paused for CSS3 Transitions
430 me.currentIteration = 0;
432 me.fireEvent('lastframe', me, me.startTime);
437 * Fire afteranimate event and end the animation. Usually called automatically when the
438 * animation reaches its final frame, but can also be called manually to pre-emptively
439 * stop and destroy the running animation.
446 Ext.fx.Manager.removeAnim(me);
447 me.fireEvent('afteranimate', me, me.startTime);
450 // Set flag to indicate that Fx is available. Class might not be available immediately.