/touch/src/draw/modifier/Animation.js
JavaScript | 431 lines | 293 code | 44 blank | 94 comment | 60 complexity | 1d3c45ce3773efb3791e90e827b0b647 MD5 | raw file
- /**
- * The Animation modifier.
- *
- * Sencha Touch allows users to use transitional animation on sprites. Simply set the duration
- * and easing in the animation modifier, then all the changes to the sprites will be animated.
- *
- * Also, you can use different durations and easing functions on different attributes by using
- * {@link #customDuration} and {@link #customEasings}.
- *
- * By default, an animation modifier will be created during the initialization of a sprite.
- * You can get the modifier of `sprite` by `sprite.fx`.
- *
- */
- Ext.define("Ext.draw.modifier.Animation", {
- mixins: {
- observable: 'Ext.mixin.Observable'
- },
- requires: [
- 'Ext.draw.TimingFunctions',
- 'Ext.draw.Animator'
- ],
- extend: 'Ext.draw.modifier.Modifier',
- alias: 'modifier.animation',
- config: {
- /**
- * @cfg {Function} easing
- * Default easing function.
- */
- easing: function (x) {
- return x;
- },
- /**
- * @cfg {Number} duration
- * Default duration time (ms).
- */
- duration: 0,
- /**
- * @cfg {Object} customEasings Overrides the default easing function for defined attributes.
- */
- customEasings: {},
- /**
- * @cfg {Object} customDuration Overrides the default duration for defined attributes.
- */
- customDuration: {}
- },
- constructor: function () {
- this.anyAnimation = false;
- this.anySpecialAnimations = false;
- this.animating = 0;
- this.animatingPool = [];
- this.callSuper(arguments);
- },
- /**
- * @inheritdoc
- */
- prepareAttributes: function (attr) {
- if (!attr.hasOwnProperty('timers')) {
- attr.animating = false;
- attr.timers = {};
- attr.animationOriginal = Ext.Object.chain(attr);
- attr.animationOriginal.upperLevel = attr;
- }
- if (this._previous) {
- this._previous.prepareAttributes(attr.animationOriginal);
- }
- },
- updateSprite: function (sprite) {
- // Apply the config that was configured in the sprite.
- this.setConfig(sprite.config.fx);
- },
- updateDuration: function (duration) {
- this.anyAnimation = duration > 0;
- },
- applyEasing: function (easing) {
- if (typeof easing === 'string') {
- return Ext.draw.TimingFunctions.easingMap[easing];
- } else {
- return easing;
- }
- },
- applyCustomEasings: function (newCustomEasing, oldCustomEasing) {
- oldCustomEasing = oldCustomEasing || {};
- var attr, attrs, easing, i, ln;
- for (attr in newCustomEasing) {
- easing = newCustomEasing[attr];
- attrs = attr.split(',');
- if (typeof easing === 'string') {
- easing = Ext.draw.TimingFunctions.easingMap[easing];
- }
- for (i = 0, ln = attrs.length; i < ln; i++) {
- oldCustomEasing[attrs[i]] = easing;
- }
- }
- return oldCustomEasing;
- },
- /**
- * Set special easings on the given attributes.
- * @param attrs The source attributes.
- * @param easing The special easings.
- */
- setEasingOn: function (attrs, easing) {
- attrs = Ext.Array.from(attrs).slice();
- var customEasing = {},
- i = 0,
- ln = attrs.length;
- for (; i < ln; i++) {
- customEasing[attrs[i]] = easing;
- }
- this.setDurationEasings(customEasing);
- },
- /**
- * Remove special easings on the given attributes.
- * @param attrs The source attributes.
- */
- clearEasingOn: function (attrs) {
- attrs = Ext.Array.from(attrs, true);
- var i = 0, ln = attrs.length;
- for (; i < ln; i++) {
- delete this._customEasing[attrs[i]];
- }
- },
- applyCustomDuration: function (newCustomDuration, oldCustomDuration) {
- oldCustomDuration = oldCustomDuration || {};
- var attr, duration, attrs, i, ln, anySpecialAnimations = this.anySpecialAnimations;
- for (attr in newCustomDuration) {
- duration = newCustomDuration[attr];
- attrs = attr.split(',');
- anySpecialAnimations = true;
- for (i = 0, ln = attrs.length; i < ln; i++) {
- oldCustomDuration[attrs[i]] = duration;
- }
- }
- this.anySpecialAnimations = anySpecialAnimations;
- return oldCustomDuration;
- },
- /**
- * Set special duration on the given attributes.
- * @param attrs The source attributes.
- * @param duration The special duration.
- */
- setDurationOn: function (attrs, duration) {
- attrs = Ext.Array.from(attrs).slice();
- var customDurations = {},
- i = 0,
- ln = attrs.length;
- for (; i < ln; i++) {
- customDurations[attrs[i]] = duration;
- }
- this.setCustomDuration(customDurations);
- },
- /**
- * Remove special easings on the given attributes.
- * @param attrs The source attributes.
- */
- clearDurationOn: function (attrs) {
- attrs = Ext.Array.from(attrs, true);
- var i = 0, ln = attrs.length;
- for (; i < ln; i++) {
- delete this._customDuration[attrs[i]];
- }
- },
- /**
- * @private
- * Initializes Animator for the animation.
- * @param attributes The source attributes.
- * @param animating The animating flag.
- */
- setAnimating: function (attributes, animating) {
- var me = this,
- i, j;
- if (attributes.animating !== animating) {
- attributes.animating = animating;
- if (animating) {
- me.animatingPool.push(attributes);
- if (me.animating === 0) {
- Ext.draw.Animator.add(me);
- }
- me.animating++;
- } else {
- for (i = 0, j = 0; i < me.animatingPool.length; i++) {
- if (me.animatingPool[i] !== attributes) {
- me.animatingPool[j++] = me.animatingPool[i];
- }
- }
- me.animating = me.animatingPool.length = j;
- }
- }
- },
- /**
- * @private
- * Set the attr with given easing and duration.
- * @param {Object} attr The attributes collection.
- * @param {Object} changes The changes that popped up from lower modifier.
- * @return {Object} The changes to pop up.
- */
- setAttrs: function (attr, changes) {
- var timers = attr.timers,
- parsers = this._sprite.self.def._animationProcessors,
- defaultEasing = this._easing,
- defaultDuration = this._duration,
- customDuration = this._customDuration,
- customEasings = this._customEasings,
- anySpecial = this.anySpecialAnimations,
- any = this.anyAnimation || anySpecial,
- original = attr.animationOriginal,
- ignite = false,
- timer, name, newValue, startValue, parser, easing, duration;
- if (!any) {
- // If there is no animation enabled
- // When applying changes to attributes, simply stop current animation
- // and set the value.
- for (name in changes) {
- if (attr[name] === changes[name]) {
- delete changes[name];
- } else {
- attr[name] = changes[name];
- }
- delete original[name];
- delete timers[name];
- }
- return changes;
- } else {
- // If any animation
- for (name in changes) {
- newValue = changes[name];
- startValue = attr[name];
- if (newValue !== startValue && any && startValue !== undefined && startValue !== null && (parser = parsers[name])) {
- // If this property is animating.
- // Figure out the desired duration and easing.
- easing = defaultEasing;
- duration = defaultDuration;
- if (anySpecial) {
- // Deducing the easing function and duration
- if (name in customEasings) {
- easing = customEasings[name];
- }
- if (name in customDuration) {
- duration = customDuration[name];
- }
- }
- // If the property is animating
- if (duration) {
- if (!timers[name]) {
- timers[name] = {};
- }
- timer = timers[name];
- timer.start = 0;
- timer.easing = easing;
- timer.duration = duration;
- timer.compute = parser.compute;
- timer.serve = parser.serve || Ext.draw.Draw.reflectFn;
- if (parser.parseInitial) {
- var initial = parser.parseInitial(startValue, newValue);
- timer.source = initial[0];
- timer.target = initial[1];
- } else if (parser.parse) {
- timer.source = parser.parse(startValue);
- timer.target = parser.parse(newValue);
- } else {
- timer.source = startValue;
- timer.target = newValue;
- }
- // The animation started. Change to originalVal.
- timers[name] = timer;
- original[name] = newValue;
- delete changes[name];
- ignite = true;
- continue;
- } else {
- delete original[name];
- }
- } else {
- delete original[name];
- }
- // If the property is not animating.
- delete timers[name];
- }
- }
- if (ignite && !attr.animating) {
- this.setAnimating(attr, true);
- }
- return changes;
- },
- /**
- * @private
- *
- * Update attributes to current value according to current animation time.
- * This method will not effect the values of lower layers, but may delete a
- * value from it.
- * @param attr The source attributes.
- * @return {Object} the changes to popup.
- */
- updateAttributes: function (attr) {
- if (!attr.animating) {
- return {};
- }
- var changes = {}, change,
- any = false,
- original = attr.animationOriginal,
- timers = attr.timers,
- now = Ext.draw.Animator.animationTime(),
- name, timer, delta;
- // If updated in the same frame, return.
- if (attr.lastUpdate === now) {
- return {};
- }
- for (name in timers) {
- timer = timers[name];
- if (!timer.start) {
- timer.start = now;
- delta = 0;
- } else {
- delta = (now - timer.start) / timer.duration;
- }
- if (delta >= 1) {
- changes[name] = original[name];
- delete original[name];
- delete timers[name];
- } else {
- changes[name] = timer.serve(timer.compute(timer.source, timer.target, timer.easing(delta), attr[name]));
- any = true;
- }
- }
- attr.lastUpdate = now;
- this.setAnimating(attr, any);
- return changes;
- },
- /**
- * @inheritdoc
- */
- pushDown: function (attr, changes) {
- changes = Ext.draw.modifier.Modifier.prototype.pushDown.call(this, attr.animationOriginal, changes);
- return this.setAttrs(attr, changes);
- },
- /**
- * @inheritdoc
- */
- popUp: function (attr, changes) {
- attr = attr.upperLevel;
- changes = this.setAttrs(attr, changes);
- if (this._next) {
- return this._next.popUp(attr, changes);
- } else {
- return Ext.apply(attr, changes);
- }
- },
- // This is called as an animated object in `Ext.draw.Animator`.
- step: function () {
- var me = this,
- pool = me.animatingPool.slice(),
- attributes,
- i, ln;
- for (i = 0, ln = pool.length; i < ln; i++) {
- attributes = pool[i];
- var changes = this.updateAttributes(attributes),
- name;
- // Looking for anything in changes
- //noinspection LoopStatementThatDoesntLoopJS
- for (name in changes) {
- if (this._next) {
- this._next.popUp(attributes, changes);
- }
- break;
- }
- }
- },
- /**
- * Stop all animations effected by this modifier
- */
- stop: function () {
- this.step();
- var me = this,
- pool = me.animatingPool,
- i, ln;
- for (i = 0, ln = pool.length; i < ln; i++) {
- pool[i].animating = false;
- }
- me.animatingPool.length = 0;
- me.animating = 0;
- Ext.draw.Animator.remove(me);
- },
- destroy: function () {
- var me = this;
- me.animatingPool.length = 0;
- me.animating = 0;
- }
- });