Форк Rambox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
12 KiB

/**
* 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.dom.Element}, {@link Ext.CompositeElement},
* {@link Ext.draw.sprite.Sprite}, {@link Ext.draw.sprite.Composite}, 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#keyframes keyframes} which follow 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#beforeanimate beforeanimate},
* {@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
* }
* });
* });
* }
*/
Ext.define('Ext.util.Animate', {
mixinId: 'animate',
requires: [
'Ext.fx.Manager',
'Ext.fx.Anim'
],
isAnimate: true,
/**
* Performs custom animation on this object.
*
* This method is applicable to both the {@link Ext.Component Component} class and the {@link Ext.draw.sprite.Sprite Sprite}
* class. It performs animated transitions of certain properties of this object over a specified timeline.
*
* ### Animating a {@link Ext.Component Component}
*
* When animating a Component, the following properties may be specified in `from`, `to`, and `keyframe` objects:
*
* - `x` - The Component's page X position in pixels.
*
* - `y` - The Component's page Y position in pixels
*
* - `left` - The Component's `left` value in pixels.
*
* - `top` - The Component's `top` value in pixels.
*
* - `width` - The Component's `width` value in pixels.
*
* - `height` - The Component's `height` value in pixels.
*
* - `dynamic` - Specify as true to update the Component's layout (if it is a Container) at every frame of the animation.
* *Use sparingly as laying out on every intermediate size change is an expensive operation.*
*
* 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%',
* margin: '5 0 5 5',
* flex: 1
* }, {
* title: 'Left: 66%',
* margin: '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 Configuration for {@link Ext.fx.Anim}.
* Note that the {@link Ext.fx.Anim#to to} config is required.
* @return {Object} this
*/
animate: function(animObj) {
var me = this;
if (Ext.fx.Manager.hasFxBlock(me.id)) {
return me;
}
Ext.fx.Manager.queueFx(new 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);
},
// @private - get animation properties
getAnimationProps: function() {
var me = this,
layout = me.layout;
return layout && layout.animate ? layout.animate : {};
},
/**
* Stops any running effects and clears this object's internal effects queue if it contains any additional effects
* that haven't started yet.
* @deprecated 4.0 Replaced by {@link #stopAnimation}
* @return {Ext.dom.Element} The Element
* @method
*/
stopFx: Ext.Function.alias(Ext.util.Animate, '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.dom.Element} The Element
*/
stopAnimation: function() {
Ext.fx.Manager.stopAnimation(this.id);
return this;
},
/**
* Ensures that all effects queued after syncFx is called on this object are run concurrently. This is the opposite
* of {@link #sequenceFx}.
* @return {Object} this
*/
syncFx: function() {
Ext.fx.Manager.setFxDefaults(this.id, {
concurrent: true
});
return this;
},
/**
* Ensures that all effects queued after sequenceFx is called on this object are run in sequence. This is the
* opposite of {@link #syncFx}.
* @return {Object} this
*/
sequenceFx: function() {
Ext.fx.Manager.setFxDefaults(this.id, {
concurrent: false
});
return this;
},
/**
* @deprecated 4.0 Replaced by {@link #getActiveAnimation}
* @inheritdoc Ext.util.Animate#getActiveAnimation
* @method
*/
hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'),
/**
* Returns the current animation if this object has any effects actively running or queued, else returns false.
* @return {Ext.fx.Anim/Boolean} Anim if element has active effects, else false
*/
getActiveAnimation: function() {
return Ext.fx.Manager.getActiveAnimation(this.id);
}
});