microsoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemail
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.
512 lines
15 KiB
512 lines
15 KiB
/** |
|
* This class manages animation for a specific {@link #target}. The animation allows |
|
* animation of various properties on the target, such as size, position, color and others. |
|
* |
|
* ## Starting Conditions |
|
* |
|
* The starting conditions for the animation are provided by the {@link #from} configuration. |
|
* Any/all of the properties in the {@link #from} configuration can be specified. If a particular |
|
* property is not defined, the starting value for that property will be read directly from the target. |
|
* |
|
* ## End Conditions |
|
* |
|
* The ending conditions for the animation are provided by the {@link #to} configuration. These mark |
|
* the final values once the animations has finished. The values in the {@link #from} can mirror |
|
* those in the {@link #to} configuration to provide a starting point. |
|
* |
|
* ## Other Options |
|
* |
|
* - {@link #duration}: Specifies the time period of the animation. |
|
* - {@link #easing}: Specifies the easing of the animation. |
|
* - {@link #iterations}: Allows the animation to repeat a number of times. |
|
* - {@link #alternate}: Used in conjunction with {@link #iterations}, reverses the direction every second iteration. |
|
* |
|
* ## Example Code |
|
* |
|
* @example |
|
* var myComponent = Ext.create('Ext.Component', { |
|
* renderTo: document.body, |
|
* width: 200, |
|
* height: 200, |
|
* style: 'border: 1px solid red;' |
|
* }); |
|
* |
|
* Ext.create('Ext.fx.Anim', { |
|
* target: myComponent, |
|
* duration: 1000, |
|
* from: { |
|
* width: 400 //starting width 400 |
|
* }, |
|
* to: { |
|
* width: 300, //end width 300 |
|
* height: 300 // end height 300 |
|
* } |
|
* }); |
|
*/ |
|
Ext.define('Ext.fx.Anim', { |
|
|
|
/* Begin Definitions */ |
|
|
|
mixins: { |
|
observable: 'Ext.util.Observable' |
|
}, |
|
|
|
requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'], |
|
|
|
/* End Definitions */ |
|
|
|
/** |
|
* @property {Boolean} isAnimation |
|
* `true` in this class to identify an object as an instantiated Anim, or subclass thereof. |
|
*/ |
|
isAnimation: true, |
|
|
|
/** |
|
* @cfg {Function/String} callback |
|
* A function to be run after the animation has completed. |
|
* @declarativeHandler |
|
*/ |
|
|
|
/** |
|
* @cfg {Object} scope |
|
* The scope that the {@link #callback} function will be called with |
|
*/ |
|
|
|
/** |
|
* @cfg {Boolean} remove |
|
* `true` to remove the target when the animation is complete, using the appropriate removal |
|
* method for the target. For example, a component will be destroyed, elements will be removed. |
|
*/ |
|
|
|
/** |
|
* @cfg {Number} duration |
|
* Time in milliseconds for a single animation to last. If the {@link #iterations} property is |
|
* specified, then each animate will take the same duration for each iteration. |
|
*/ |
|
duration: 250, |
|
|
|
/** |
|
* @cfg {Number} delay |
|
* Time to delay before starting the animation. |
|
*/ |
|
delay: 0, |
|
|
|
/* @private used to track a delayed starting time */ |
|
delayStart: 0, |
|
|
|
/** |
|
* @cfg {Boolean} dynamic |
|
* 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. |
|
*/ |
|
dynamic: false, |
|
|
|
/** |
|
* @cfg {String} easing |
|
* This describes how the intermediate values used during a transition will be calculated. |
|
* It allows for a transition to change speed over its duration. |
|
* |
|
* - backIn |
|
* - backOut |
|
* - bounceIn |
|
* - bounceOut |
|
* - ease |
|
* - easeIn |
|
* - easeOut |
|
* - easeInOut |
|
* - elasticIn |
|
* - elasticOut |
|
* - cubic-bezier(x1, y1, x2, y2) |
|
* |
|
* Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0] |
|
* specification. The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must |
|
* be in the range [0, 1] or the definition is invalid. |
|
* |
|
* [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag |
|
*/ |
|
easing: 'ease', |
|
|
|
/** |
|
* @cfg {Object} keyframes |
|
* Animation keyframes follow the CSS3 Animation configuration pattern. 'from' is always considered '0%' and 'to' |
|
* is considered '100%'. **Every keyframe declaration must have a keyframe rule for 0% and 100%, possibly defined using |
|
* "from" or "to".** A keyframe declaration without these keyframe selectors is invalid and will not be available for |
|
* animation. The keyframe declaration for a keyframe rule consists of properties and values. Properties that are unable to |
|
* be animated are ignored in these rules, with the exception of 'easing' which can be changed at each keyframe. For example: |
|
* |
|
* keyframes : { |
|
* '0%': { |
|
* left: 100 |
|
* }, |
|
* '40%': { |
|
* left: 150 |
|
* }, |
|
* '60%': { |
|
* left: 75 |
|
* }, |
|
* '100%': { |
|
* left: 100 |
|
* } |
|
* } |
|
*/ |
|
|
|
/** |
|
* @private |
|
*/ |
|
damper: 1, |
|
|
|
/** |
|
* @private |
|
*/ |
|
bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, |
|
|
|
/** |
|
* Run the animation from the end to the beginning |
|
* Defaults to false. |
|
* @cfg {Boolean} reverse |
|
*/ |
|
reverse: false, |
|
|
|
/** |
|
* Flag to determine if the animation has started |
|
* @property running |
|
* @type Boolean |
|
*/ |
|
running: false, |
|
|
|
/** |
|
* Flag to determine if the animation is paused. Only set this to true if you need to |
|
* keep the Anim instance around to be un-paused later; otherwise call {@link #end}. |
|
* @property paused |
|
* @type Boolean |
|
*/ |
|
paused: false, |
|
|
|
/** |
|
* @cfg {Number} iterations |
|
* Number of times to execute the animation. |
|
*/ |
|
iterations: 1, |
|
|
|
/** |
|
* @cfg {Boolean} autoEnd |
|
* `true` to immediately force this animation to its final state. This can be useful |
|
* in cases where you want the final effect of an animation, but need to the actual |
|
* animation dynamically. Also see the {@link #jumpToEnd} method. |
|
*/ |
|
autoEnd: false, |
|
|
|
/** |
|
* @cfg {Boolean} alternate |
|
* Used in conjunction with iterations to reverse the animation each time an iteration completes. |
|
*/ |
|
alternate: false, |
|
|
|
/** |
|
* Current iteration the animation is running. |
|
* @property currentIteration |
|
* @type Number |
|
*/ |
|
currentIteration: 0, |
|
|
|
/** |
|
* Starting time of the animation. |
|
* @property startTime |
|
* @type Date |
|
*/ |
|
startTime: 0, |
|
|
|
/** |
|
* Contains a cache of the interpolators to be used. |
|
* @private |
|
* @property propHandlers |
|
* @type Object |
|
*/ |
|
|
|
/** |
|
* @cfg {String/Object} target |
|
* The {@link Ext.fx.target.Target} to apply the animation to. This should only be specified when creating an Ext.fx.Anim directly. |
|
* The target does not need to be a {@link Ext.fx.target.Target} instance, it can be the underlying object. For example, you can |
|
* pass a Component, Element or Sprite as the target and the Anim will create the appropriate {@link Ext.fx.target.Target} object |
|
* automatically. |
|
*/ |
|
|
|
/** |
|
* @cfg {Object} from |
|
* An object containing property/value pairs for the beginning of the animation. If not specified, the current state of the |
|
* Ext.fx.target will be used. For example: |
|
* |
|
* from: { |
|
* opacity: 0, // Transparent |
|
* color: '#ffffff', // White |
|
* left: 0 |
|
* } |
|
* |
|
*/ |
|
|
|
/** |
|
* @cfg {Object} to (required) |
|
* An object containing property/value pairs for the end of the animation. For example: |
|
* |
|
* to: { |
|
* opacity: 1, // Opaque |
|
* color: '#00ff00', // Green |
|
* left: 500 |
|
* } |
|
* |
|
*/ |
|
|
|
// @private |
|
frameCount: 0, |
|
|
|
/** |
|
* @event beforeanimate |
|
* Fires before the animation starts. A handler can return false to cancel the animation. |
|
* @param {Ext.fx.Anim} this |
|
*/ |
|
|
|
/** |
|
* @event afteranimate |
|
* Fires when the animation is complete. |
|
* @param {Ext.fx.Anim} this |
|
* @param {Date} startTime |
|
*/ |
|
|
|
/** |
|
* @event lastframe |
|
* Fires when the animation's last frame has been set. |
|
* @param {Ext.fx.Anim} this |
|
* @param {Date} startTime |
|
*/ |
|
|
|
// @private |
|
constructor: function(config) { |
|
var me = this, |
|
curve; |
|
|
|
config = config || {}; |
|
// If keyframes are passed, they really want an Animator instead. |
|
if (config.keyframes) { |
|
return new Ext.fx.Animator(config); |
|
} |
|
Ext.apply(me, config); |
|
if (me.from === undefined) { |
|
me.from = {}; |
|
} |
|
me.propHandlers = {}; |
|
me.config = config; |
|
me.target = Ext.fx.Manager.createTarget(me.target); |
|
me.easingFn = Ext.fx.Easing[me.easing]; |
|
me.target.dynamic = me.dynamic; |
|
|
|
// If not a pre-defined curve, try a cubic-bezier |
|
if (!me.easingFn) { |
|
me.easingFn = String(me.easing).match(me.bezierRE); |
|
if (me.easingFn && me.easingFn.length === 5) { |
|
curve = me.easingFn; |
|
me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]); |
|
} |
|
} |
|
me.id = Ext.id(null, 'ext-anim-'); |
|
|
|
me.mixins.observable.constructor.call(me); |
|
Ext.fx.Manager.addAnim(me); |
|
if (config.autoEnd) { |
|
me.running = true; |
|
me.jumpToEnd(); |
|
} |
|
}, |
|
|
|
/** |
|
* @private |
|
* Helper to the target |
|
*/ |
|
setAttr: function(attr, value) { |
|
return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value); |
|
}, |
|
|
|
/** |
|
* @private |
|
* Set up the initial currentAttrs hash. |
|
*/ |
|
initAttrs: function() { |
|
var me = this, |
|
from = me.from, |
|
to = me.to, |
|
initialFrom = me.initialFrom || {}, |
|
out = {}, |
|
start, end, propHandler, attr; |
|
|
|
for (attr in to) { |
|
if (to.hasOwnProperty(attr)) { |
|
start = me.target.getAttr(attr, from[attr]); |
|
end = to[attr]; |
|
// Use default (numeric) property handler |
|
if (!Ext.fx.PropertyHandler[attr]) { |
|
if (Ext.isObject(end)) { |
|
propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object; |
|
} else { |
|
propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler; |
|
} |
|
} |
|
// Use custom handler |
|
else { |
|
propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr]; |
|
} |
|
out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr); |
|
} |
|
} |
|
me.currentAttrs = out; |
|
}, |
|
|
|
/** |
|
* @private |
|
* Fires beforeanimate and sets the running flag. |
|
*/ |
|
start: function(startTime) { |
|
var me = this, |
|
delay = me.delay, |
|
delayStart = me.delayStart, |
|
delayDelta; |
|
|
|
if (delay) { |
|
if (!delayStart) { |
|
me.delayStart = startTime; |
|
return; |
|
} |
|
else { |
|
delayDelta = startTime - delayStart; |
|
if (delayDelta < delay) { |
|
return; |
|
} |
|
else { |
|
// Compensate for frame delay; |
|
startTime = new Date(delayStart.getTime() + delay); |
|
} |
|
} |
|
} |
|
if (me.fireEvent('beforeanimate', me) !== false) { |
|
me.startTime = startTime; |
|
if (!me.paused && !me.currentAttrs) { |
|
me.initAttrs(); |
|
} |
|
me.running = true; |
|
me.frameCount = 0; |
|
} |
|
}, |
|
|
|
/** |
|
* Immediately force this animation to its final state. |
|
*/ |
|
jumpToEnd: function(){ |
|
var me = this; |
|
|
|
if (!me.endWasCalled) { |
|
if (!me.currentAttrs) { |
|
me.initAttrs(); |
|
} |
|
Ext.fx.Manager.jumpToEnd(me); |
|
me.end(); |
|
} |
|
}, |
|
|
|
/** |
|
* @private |
|
* Calculate attribute value at the passed timestamp. |
|
* @return a hash of the new attributes. |
|
*/ |
|
runAnim: function(elapsedTime) { |
|
var me = this, |
|
attrs = me.currentAttrs, |
|
duration = me.duration, |
|
easingFn = me.easingFn, |
|
propHandlers = me.propHandlers, |
|
ret = {}, |
|
easing, values, attr, lastFrame; |
|
|
|
if (elapsedTime >= duration) { |
|
elapsedTime = duration; |
|
lastFrame = true; |
|
} |
|
if (me.reverse) { |
|
elapsedTime = duration - elapsedTime; |
|
} |
|
|
|
for (attr in attrs) { |
|
if (attrs.hasOwnProperty(attr)) { |
|
values = attrs[attr]; |
|
easing = lastFrame ? 1 : easingFn(elapsedTime / duration); |
|
ret[attr] = propHandlers[attr].set(values, easing); |
|
} |
|
} |
|
me.frameCount++; |
|
|
|
return ret; |
|
}, |
|
|
|
/** |
|
* @private |
|
* Perform lastFrame cleanup and handle iterations |
|
* @return a hash of the new attributes. |
|
*/ |
|
lastFrame: function() { |
|
var me = this, |
|
iter = me.iterations, |
|
iterCount = me.currentIteration; |
|
|
|
iterCount++; |
|
if (iterCount < iter) { |
|
if (me.alternate) { |
|
me.reverse = !me.reverse; |
|
} |
|
me.startTime = new Date(); |
|
me.currentIteration = iterCount; |
|
// Turn off paused for CSS3 Transitions |
|
me.paused = false; |
|
} |
|
else { |
|
me.currentIteration = 0; |
|
me.end(); |
|
me.fireEvent('lastframe', me, me.startTime); |
|
} |
|
}, |
|
|
|
endWasCalled: 0, |
|
|
|
/** |
|
* Fire afteranimate event and end the animation. Usually called automatically when the |
|
* animation reaches its final frame, but can also be called manually to preemptively |
|
* stop and destroy the running animation. |
|
*/ |
|
end: function() { |
|
var me = this; |
|
if (me.endWasCalled++) { |
|
return; |
|
} |
|
|
|
me.startTime = 0; |
|
me.paused = false; |
|
me.running = false; |
|
Ext.fx.Manager.removeAnim(me); |
|
me.fireEvent('afteranimate', me, me.startTime); |
|
Ext.callback(me.callback, me.scope, [me, me.startTime]); |
|
if (me.remove) { |
|
me.target.destroy(); |
|
} |
|
}, |
|
|
|
isReady: function() { |
|
return this.paused === false && this.running === false && this.iterations > 0; |
|
}, |
|
|
|
isRunning: function() { |
|
return this.paused === false && this.running === true && this.isAnimator !== true; |
|
} |
|
}); |
|
|
|
/** |
|
* @member Ext |
|
* @property {Boolean} enableFx |
|
* True if the {@link Ext.fx.Anim} Class is available. |
|
*/ |
|
Ext.enableFx = true; // Indicate that Fx is available. Class might not be available immediately.
|
|
|