Source: utils/Tween.js

/**
 * A wrapper around PIXI.tween OR CreateJS/TweenJS to do animations/tweening,
 * for example for a List or a Scroller.
 *
 * @see GOWN.Scroller#throwTo
 *
 * @constructor
 * @memberof GOWN
 * @param target The tween target {Object}
 * @param duration The tween duration {Number}
 * @param [easing='linear'] The easing function name {String}
 * @param [type] The tween library {String}
 */
//TODO: support greensock?
function Tween(target, duration, easing, type) {
    /**
     * The tween duration
     *
     * @type Number
     */
    this.duration = duration;

    /**
     * The easing function name
     *
     * @type String
     * @default 'linear'
     */
    this.easing = easing || 'linear';

    /**
     * The tween library
     *
     * @type String
     */
    this.type = type || this.checkLibrary();
    if (this.type === Tween.NONE) {
        /**
         * The tween target
         *
         * @private
         * @type Object
         */
        this._target = target;
    }
    this.createTween(target, duration, easing);
}

Tween.prototype = Object.create({});
Tween.prototype.constructor = Tween;
module.exports = Tween;

/**
 * The PIXI tween type
 *
 * @static
 * @final
 * @type String
 */
Tween.PIXI_TWEEN = 'PIXI_TWEEN';

/**
 * The CreateJS tween type
 *
 * @static
 * @final
 * @type String
 */
Tween.CREATEJS_TWEEN = 'CREATEJS_TWEEN';

/**
 * No tween type
 *
 * @static
 * @final
 * @type String
 */
Tween.NONE = 'NONE';

/**
 * Uppercase the first letter. Does NOT work like capitalize in python.
 * It just capitalizes the first letter and let the other characters untouched.
 *
 * @param string The string to capitalize {String}
 * @return {String} The capitalized string
 */
function capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

// TODO: possible alternative: create own easing data type
// e.g. (in, out, inout and type)

/**
 * Get the specific CreateJS easing function (e.g. 'linear' or 'quadIn')
 *
 * @param ease The name of the CreateJS easing function {String}
 * @return {function}
 */
Tween.CREATEJS_EASING = function(ease) {
    // inQutQuad to quadInOut
    if (ease.substring(0, 5) === 'inOut') {
        ease = ease.slice(5).toLowerCase() + 'InOut';
    }
    // inQuad to quadIn
    if (ease.substring(0, 2) === 'in') {
        ease = ease.slice(2).toLowerCase() + 'In';
    }
    if (ease.substring(0, 3) === 'out') {
        ease = ease.slice(3).toLowerCase() + 'Out';
    }
    return createjs.Ease[ease];
};

/**
 * Get the specific PIXI easing function
 *
 * @param ease The name of the PIXI easing function {String}
 * @return {function}
 */
Tween.PIXI_EASING = function(ease) {
    if (ease.substring(ease.length-5) === 'InOut') {
        ease = 'inOut' + capitalize(ease.slice(0, -5));
    }
    if (ease.substring(ease.length-3) === 'Out') {
        ease = 'out' + capitalize(ease.slice(0, -3));
    }
    if (ease.substring(ease.length-2) === 'In') {
        ease = 'in' + capitalize(ease.slice(0, -2));
    }
    return PIXI.tween.Easing[ease]();
};

/**
 * A helper function to check if a tweening-library is present
 *
 * @return {String} Name of the tweening-library
 */
Tween.prototype.checkLibrary = function() {
    if (window.PIXI && PIXI.tween) {
        return Tween.PIXI_TWEEN;
    } else if (window.createjs && window.createjs.Tween) {
        return Tween.CREATEJS_TWEEN;
    } else {
        return Tween.NONE;
    }
};

/**
 * Create a tween
 *
 * @param target The tween target {Object}
 * @param duration The tween duration {Number}
 * @param easing The easing function name {String}
 */
Tween.prototype.createTween = function(target, duration, easing) {
    if (this.type === Tween.PIXI_TWEEN) {
        this._tween = PIXI.tweenManager.createTween(target);
        // tweenjs stores time in ms
        this._tween.time = duration;
        // Easing is a function in PIXI.tween.Easing
        this._tween.easing = Tween.PIXI_EASING(easing);
    } else if (this.type === Tween.CREATEJS_TWEEN) {
        createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED;
        createjs.Ticker.setFPS(60);
        this._tween = createjs.Tween.get(target, {loop: false});
    } else {
        this._tween = null;
    }
};

/**
 * Start the tween
 *
 * @param data The tween data {Object}
 */
Tween.prototype.to = function(data) {
    if (this.type === Tween.PIXI_TWEEN && this._tween) {
        this._tween.stop();
        this._tween.to(data);
        this._tween.start();
    } else if (this.type === Tween.CREATEJS_TWEEN && this._tween) {
        this._tween.to(data, this.duration, Tween.CREATEJS_EASING(this.easing));
        this._tween.play();
    } else if (this.type === Tween.NONE) {
        // no tween, set values directly and without wait
        // maybe we'd like to do some basic linear transitioning
        // in the future even if there is nothing set?
        for (var key in data) {
            this._target[key] = data[key];
        }
    }
};

/**
 * Stop the tween
 */
Tween.prototype.remove = function() {
    if (this.type === Tween.PIXI_TWEEN && this._tween) {
        PIXI.tween.TweenManager.removeTween(this._tween);
    }
    this._tween = null;
};