/** * @class Ext.util.Animate * This animation class is a mixin. Ext.util.Animate provides an API for the creation of animated transitions of properties and styles. This class is used as a mixin and currently applied to {@link Ext.Element}, {@link Ext.CompositeElement}, {@link Ext.draw.Sprite}, {@link Ext.draw.SpriteGroup}, and {@link Ext.Component}. Note that Components have a limited subset of what attributes can be animated such as top, left, x, y, height, width, and opacity (color, paddings, and margins can not be animated). __Animation Basics__ All animations require three things - easing, duration, and to (the final end value for each property) you wish to animate. Easing and duration are defaulted values specified below. Easing describes how the intermediate values used during a transition will be calculated. {@link Ext.fx.Anim#easing Easing} allows for a transition to change speed over its duration. You may use the defaults for easing and duration, but you must always set a {@link Ext.fx.Anim#to to} property which is the end value for all animations. Popular element 'to' configurations are: opacity, x, y, color, height, width Popular sprite 'to' configurations are: translation, path, scale, stroke, rotation The default duration for animations is 250 (which is a 1/4 of a second). Duration is denoted in milliseconds. Therefore 1 second is 1000, 1 minute would be 60000, and so on. The default easing curve used for all animations is 'ease'. Popular easing functions are included and can be found in {@link Ext.fx.Anim#easing Easing}. For example, a simple animation to fade out an element with a default easing and duration: var p1 = Ext.get('myElementId'); p1.animate({ to: { opacity: 0 } }); To make this animation fade out in a tenth of a second: var p1 = Ext.get('myElementId'); p1.animate({ duration: 100, to: { opacity: 0 } }); __Animation Queues__ By default all animations are added to a queue which allows for animation via a chain-style API. For example, the following code will queue 4 animations which occur sequentially (one right after the other): p1.animate({ to: { x: 500 } }).animate({ to: { y: 150 } }).animate({ to: { backgroundColor: '#f00' //red } }).animate({ to: { opacity: 0 } }); You can change this behavior by calling the {@link Ext.util.Animate#syncFx syncFx} method and all subsequent animations for the specified target will be run concurrently (at the same time). p1.syncFx(); //this will make all animations run at the same time p1.animate({ to: { x: 500 } }).animate({ to: { y: 150 } }).animate({ to: { backgroundColor: '#f00' //red } }).animate({ to: { opacity: 0 } }); This works the same as: p1.animate({ to: { x: 500, y: 150, backgroundColor: '#f00' //red opacity: 0 } }); The {@link Ext.util.Animate#stopFx stopFx} method can be used to stop any currently running animations and clear any queued animations. __Animation Keyframes__ You can also set up complex animations with {@link Ext.fx.Anim#keyframe keyframe} which follows the CSS3 Animation configuration pattern. Note rotation, translation, and scaling can only be done for sprites. The previous example can be written with the following syntax: p1.animate({ duration: 1000, //one second total keyframes: { 25: { //from 0 to 250ms (25%) x: 0 }, 50: { //from 250ms to 500ms (50%) y: 0 }, 75: { //from 500ms to 750ms (75%) backgroundColor: '#f00' //red }, 100: { //from 750ms to 1sec opacity: 0 } } }); __Animation Events__ Each animation you create has events for {@link Ext.fx.Anim#beforeanimation beforeanimation}, {@link Ext.fx.Anim#afteranimation afteranimation}, and {@link Ext.fx.Anim#lastframe lastframe}. Keyframed animations adds an additional {@link Ext.fx.Animator#keyframe keyframe} event which fires for each keyframe in your animation. All animations support the {@link Ext.util.Observable#listeners listeners} configuration to attact functions to these events. startAnimate: function() { var p1 = Ext.get('myElementId'); p1.animate({ duration: 100, to: { opacity: 0 }, listeners: { beforeanimate: function() { // Execute my custom method before the animation this.myBeforeAnimateFn(); }, afteranimate: function() { // Execute my custom method after the animation this.myAfterAnimateFn(); }, scope: this }); }, myBeforeAnimateFn: function() { // My custom logic }, myAfterAnimateFn: function() { // My custom logic } Due to the fact that animations run asynchronously, you can determine if an animation is currently running on any target by using the {@link Ext.util.Animate#hasActiveFx hasActiveFx} method. This method will return false if there are no active animations or return the currently running {@link Ext.fx.Anim} instance. In this example, we're going to wait for the current animation to finish, then stop any other queued animations before we fade our element's opacity to 0: var curAnim = p1.hasActiveFx(); if (curAnim) { curAnim.on('afteranimate', function() { p1.stopFx(); p1.animate({ to: { opacity: 0 } }); }); } * * @markdown * @docauthor Jamie Avins <jamie@sencha.com> */ Ext.define('Ext.util.Animate', { uses: ['Ext.fx.Manager', 'Ext.fx.Anim'], /** * Perform custom animation on this element. * @param {Ext.fx.Anim} animObj An Ext.fx Anim object * @return {Ext.core.Element} this */ animate: function(animObj) { var me = this; if (Ext.fx.Manager.hasFxBlock(me.id)) { return me; } Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(animObj))); return this; }, // @private - process the passed fx configuration. anim: function(config) { if (!Ext.isObject(config)) { return (config) ? {} : false; } var me = this; if (config.stopFx) { me.stopFx(); } Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id)); return Ext.apply({ target: me, paused: true }, config); }, /** * Stops any running effects and clears the element's internal effects queue if it contains * any additional effects that haven't started yet. * @return {Ext.core.Element} The Element */ stopFx: function() { Ext.fx.Manager.stopFx(this.id); }, /** * Ensures that all effects queued after syncFx is called on the element are * run concurrently. This is the opposite of {@link #sequenceFx}. * @return {Ext.core.Element} The Element */ syncFx: function() { Ext.fx.Manager.setFxDefaults(this.id, { concurrent: true }); }, /** * Ensures that all effects queued after sequenceFx is called on the element are * run in sequence. This is the opposite of {@link #syncFx}. * @return {Ext.core.Element} The Element */ sequenceFx: function() { Ext.fx.Manager.setFxDefaults(this.id, { concurrent: false }); }, /** * Returns thq current animation if the element has any effects actively running or queued, else returns false. * @return {Mixed} anim if element has active effects, else false */ hasActiveFx: function() { return Ext.fx.Manager.hasActiveFx(this.id); } }); // Apply Animate mixin manually until Element is defined in the proper 4.x way Ext.applyIf(Ext.core.Element.prototype, Ext.util.Animate.prototype);