/* * @class Ext.util.translatable.Abstract * @private * * The abstract class. Sub-classes are expected, at the very least, to implement translation logics inside * the 'translate' method */ Ext.define('Ext.util.translatable.Abstract', { mixins: ['Ext.mixin.Observable'], requires: ['Ext.fx.Easing'], config: { element: null, easing: {}, easingX: {}, easingY: {}, fps: 60 }, constructor: function(config) { var element; this.doAnimationFrame = Ext.Function.bind(this.doAnimationFrame, this); this.translation = { x: 0, y: 0 }; this.activeEasing = { x: null, y: null }; this.initialConfig = config; if (config && config.element) { element = config.element; delete config.element; this.setElement(element); } }, applyElement: function(element) { if (!element) { return; } return Ext.get(element); }, updateElement: function(element) { this.initConfig(this.initialConfig); this.refresh(); }, factoryEasing: function(easing) { return new Ext.fx.Easing(easing); }, applyEasing: function(easing) { easing = this.factoryEasing(easing); if (!this.getEasingX()) { this.setEasingX(easing); } if (!this.getEasingY()) { this.setEasingY(easing); } return easing; }, applyEasingX: function(easing) { return this.factoryEasing(easing); }, applyEasingY: function(easing) { return this.factoryEasing(easing); }, updateFps: function(fps) { this.animationInterval = 1000 / fps; }, doTranslate: function(translation) { var current = this.translation; if ('x' in translation) { current.x = translation.x; } if ('y' in translation) { current.y = translation.y; } return this; }, translate: function(translation, animation) { this.stopAnimation(); if (animation) { return this.translateAnimated(translation, animation); } return this.doTranslate(translation); }, translateAnimated: function(translation, animation) { if (!Ext.isObject(animation)) { animation = {}; } var easing = animation.easing, activeEasing = this.activeEasing, current = this.translation, now = Ext.Date.now(), easingX = ('x' in translation) ? (easing || animation.easingX || this.getEasingX()) : null, easingY = ('y' in translation) ? (easing || animation.easingY || this.getEasingY()) : null; if (easingX) { easingX = this.factoryEasing(easingX); easingX.setStartTime(now); easingX.setStartValue(current.x); easingX.setEndValue(translation.x); if ('duration' in animation) { easingX.setDuration(animation.duration); } } if (easingY) { easingY = this.factoryEasing(easingY); easingY.setStartTime(now); easingY.setStartValue(current.y); easingY.setEndValue(translation.y); if ('duration' in animation) { easingY.setDuration(animation.duration); } } activeEasing.x = easingX; activeEasing.y = easingY; this.isAnimating = true; this.animationTimer = setInterval(this.doAnimationFrame, this.animationInterval, this); this.fireEvent('animationstart', this); }, doAnimationFrame: function() { if (!this.isAnimating) { return; } var easing = this.activeEasing, easingX = easing.x, easingY = easing.y, isEasingXEnded = easingX === null || easingX.isEnded, isEasingYEnded = easingY === null || easingY.isEnded, translation = {}; if (isEasingXEnded && isEasingYEnded) { this.stopAnimation(); return; } if (!isEasingXEnded) { translation.x = Math.round(easingX.getValue()); } if (!isEasingYEnded) { translation.y = Math.round(easingY.getValue()); } this.doTranslate(translation); this.fireEvent('animationframe', this, translation); }, stopAnimation: function() { if (!this.isAnimating) { return; } var activeEasing = this.activeEasing; activeEasing.x = null; activeEasing.y = null; this.isAnimating = false; clearInterval(this.animationTimer); this.fireEvent('animationend', this); }, refresh: function() { this.translate(this.translation); } });