X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/util/Animate.js diff --git a/src/util/Animate.js b/src/util/Animate.js new file mode 100644 index 00000000..ceebbd3e --- /dev/null +++ b/src/util/Animate.js @@ -0,0 +1,382 @@ +/** + * @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.core.Element}, {@link Ext.CompositeElement}, + * {@link Ext.draw.Sprite}, {@link Ext.draw.CompositeSprite}, 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#stopAnimation stopAnimation} 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#afteranimate afteranimate}, 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#getActiveAnimation getActiveAnimation} + * 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.getActiveAnimation(); + * if (curAnim) { + * curAnim.on('afteranimate', function() { + * p1.stopAnimation(); + * p1.animate({ + * to: { + * opacity: 0 + * } + * }); + * }); + * } + * + * @docauthor Jamie Avins + */ +Ext.define('Ext.util.Animate', { + + uses: ['Ext.fx.Manager', 'Ext.fx.Anim'], + + /** + *

Perform custom animation on this object.

+ *

This method is applicable to both the the {@link Ext.Component Component} class and the {@link Ext.core.Element Element} class. + * It performs animated transitions of certain properties of this object over a specified timeline.

+ *

The sole parameter is an object which specifies start property values, end property values, and properties which + * describe the timeline. Of the properties listed below, only to is mandatory.

+ *

Properties include

+ *

Animating an {@link Ext.core.Element Element}

+ * When animating an Element, the following properties may be specified in from, to, and keyframe objects: + *

Be aware than animating an Element which is being used by an Ext Component without in some way informing the Component about the changed element state + * will result in incorrect Component behaviour. This is because the Component will be using the old state of the element. To avoid this problem, it is now possible to + * directly animate certain properties of Components.

+ *

Animating a {@link Ext.Component Component}

+ * When animating an Element, the following properties may be specified in from, to, and keyframe objects: + *

For example, to animate a Window to a new size, ensuring that its internal layout, and any shadow is correct:

+ *

+myWindow = Ext.create('Ext.window.Window', {
+    title: 'Test Component animation',
+    width: 500,
+    height: 300,
+    layout: {
+        type: 'hbox',
+        align: 'stretch'
+    },
+    items: [{
+        title: 'Left: 33%',
+        margins: '5 0 5 5',
+        flex: 1
+    }, {
+        title: 'Left: 66%',
+        margins: '5 5 5 5',
+        flex: 2
+    }]
+});
+myWindow.show();
+myWindow.header.el.on('click', function() {
+    myWindow.animate({
+        to: {
+            width: (myWindow.getWidth() == 500) ? 700 : 500,
+            height: (myWindow.getHeight() == 300) ? 400 : 300,
+        }
+    });
+});
+
+ *

For performance reasons, by default, the internal layout is only updated when the Window reaches its final "to" size. If dynamic updating of the Window's child + * Components is required, then configure the animation with dynamic: true and the two child items will maintain their proportions during the animation.

+ * @param {Object} config An object containing properties which describe the animation's start and end states, and the timeline of the animation. + * @return {Object} 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.stopAnimation) { + me.stopAnimation(); + } + + Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id)); + + return Ext.apply({ + target: me, + paused: true + }, config); + }, + + /** + * Stops any running effects and clears this object's internal effects queue if it contains + * any additional effects that haven't started yet. + * @return {Ext.core.Element} The Element + */ + stopFx: Ext.Function.alias(Ext.util.Animate, 'stopAnimation'), + + /** + * @deprecated 4.0 Replaced by {@link #stopAnimation} + * Stops any running effects and clears this object's internal effects queue if it contains + * any additional effects that haven't started yet. + * @return {Ext.core.Element} The Element + */ + stopAnimation: function() { + Ext.fx.Manager.stopAnimation(this.id); + }, + + /** + * Ensures that all effects queued after syncFx is called on this object 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 this object 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 + }); + }, + + /** + * @deprecated 4.0 Replaced by {@link #getActiveAnimation} + * Returns thq current animation if this object has any effects actively running or queued, else returns false. + * @return {Mixed} anim if element has active effects, else false + */ + hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'), + + /** + * Returns thq current animation if this object has any effects actively running or queued, else returns false. + * @return {Mixed} anim if element has active effects, else false + */ + getActiveAnimation: function() { + return Ext.fx.Manager.getActiveAnimation(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); \ No newline at end of file