API Docs for: 1.4.0
Show:

File: src\animations\tweens\Tween.ts

/**
*  
* @module Animations
* @submodule Tweens 
* 
*/

module Kiwi.Animations {

	/**
	* Manages the tweening of properties/values on a single object. A Tween is the animation of a number between an initially value to and final value (that you specify). 
	* Note: When using a Tween you need to make sure that the Tween has been added to a TweenManager. You can either do this by creating the Tween via the Manager or alternatively using the 'add' method on the TweenManager. Otherwise the tween will not work.
	*
	* Based on tween.js by sole. Converted to TypeScript and integrated into Kiwi.
	* https://github.com/sole/tween.js
	*
	* @class Tween
	* @constructor
	* @namespace Kiwi.Animations
	* @param object {Any} The object that this tween is taking affect on.
	* @param game {Kiwi.Game} The game that this tween is for.
	* @return {Kiwi.Animations.Tween} This tween.
	*
	* @author     sole / http://soledadpenades.com
	* @author     mrdoob / http://mrdoob.com
	* @author     Robert Eisele / http://www.xarg.org
	* @author     Philippe / http://philippe.elsass.me
	* @author     Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html
	* @author     Paul Lewis / http://www.aerotwist.com/
	* @author     lechecacharro
	* @author     Josh Faul / http://jocafa.com/
	* @author     egraether / http://egraether.com/
	*
	*/
	export class Tween {

		constructor(object, game:Kiwi.Game = null) {

			this._object = object;

			if (game !== null)
			{
				this._game = game;
				this._manager = this._game.tweens;
			}

			this.isRunning = false;

		}

		/**
		* The type of object that this is.
		* @method objType
		* @return {String} "Tween"
		* @public
		*/
		public objType() {
			return "Tween";
		}

		/** 
		* The game that this tween belongs to.
		* @property _game
		* @type Kiwi.Game
		* @private
		*/
		private _game: Kiwi.Game = null;

		/** 
		* The manager that this tween belongs to. 
		* @property _manager
		* @type Kiwi.Animations.Tweens.TweenManager
		* @private
		*/
		private _manager: Kiwi.Animations.Tweens.TweenManager = null;

		/**
		* The manager that this tween belongs to.
		* @property manager
		* @type Kiwi.Animations.Tweens.TweenManager
		* @private
		* @since 1.2.0
		*/
		public get manager(): Kiwi.Animations.Tweens.TweenManager {
			return this._manager;
		}

		public set manager( value: Kiwi.Animations.Tweens.TweenManager ) {
			this._manager = value;
		}

		/** 
		* The object that this tween is affecting.
		* @property _object
		* @type Any
		* @private
		*/
		private _object = null;

		/**
		* The object that this tween is affecting.
		* If you change this, it will continue to tween,
		* but any properties that are not on the new object
		* will be discarded from the tween.
		* @property object
		* @type any
		* @public
		*/
		public get object(): any {
			return this._object;
		}

		public set object( value: any ) {
			var i,
				newValues = {};

			this._object = value;

			for ( i in this._valuesEnd ) {
				if ( value[ i ] ) {
					newValues[ i ] = this._valuesEnd[ i ];
				}
			}

			this._valuesEnd = newValues;
		}

		/** 
		* The starting values of the properties that the tween is animating.
		* @property _valuesStart
		* @type Object
		* @private
		*/
		private _valuesStart = {};

		/** 
		* The end values of the properties that the tween is animating.
		* @property _valuesEnd
		* @type Object
		* @private
		*/
		private _valuesEnd = {};

		/** 
		* The duration of the tween, in milliseconds.
		* @property _duration
		* @type Number
		* @private
		*/
		private _duration = 1000;

		/** 
		* The amount of time to delay the tween by. In Milliseconds.
		* @property _delayTime
		* @type Number
		* @private
		*/
		private _delayTime:number = 0;

		/** 
		* The time at which the tween started.
		* @property _startTime
		* @type Number
		* @private
		*/
		private _startTime:number = null;

		/** 
		* The easing function that is to be used while tweening.
		* @property _easingFunction
		* @type Function
		* @default Kiwi.Tweens.Easing.Linear.None
		* @private
		*/
		private _easingFunction = Kiwi.Animations.Tweens.Easing.Linear.None;

		/** 
		* [NEEDS DESCRIPTION]
		* @property _interpolationFunction
		* @type Function
		* @default Kiwi.Utils.Interpolation.Linear
		* @private
		*/
		private _interpolationFunction = Kiwi.Utils.GameMath.linearInterpolation;

		/** 
		* An array containing all of the tweens that are to be played when this one finishes.
		* @property _chainedTweens
		* @type Tween[]
		* @private
		*/
		private _chainedTweens = [];

		/** 
		* The method that is to be called when the tween starts playing.
		* @property _onStartCallback
		* @type Function
		* @default null
		* @private
		*/
		private _onStartCallback = null;

		/**
		* The context that the _onStartCallback method is to be called in. 
		* @property _onStartContext
		* @type Any
		* @default null
		* @private
		*/
		private _onStartContext:any = null;

		/** 
		* A boolean indicating if the starting callback has been called or not.
		* @property _onStartCallbackFired
		* @type boolean
		* @default false
		* @private
		*/
		private _onStartCallbackFired:boolean = false;

		/** 
		* A callback method that will be called each time the tween updates.
		* @property _onUpdateCallback
		* @type Function
		* @default null
		* @private
		*/
		private _onUpdateCallback = null;

		/**
		* The context that the update callback has when called.
		* @property _onUpdateContext
		* @type any
		* @default null
		* @private
		*/
		private _onUpdateContext:any = null;

		/** 
		* A method to be called when the tween finish's tweening.
		* @property _onCompleteCallback
		* @type function
		* @default null
		* @private
		*/
		private _onCompleteCallback = null;

		/*
		* A boolean indicating whether or not the _onCompleteCallback has been called.
		* Is reset each time you tell the tween to start.
		* @property _onCompleteCalled
		* @type boolean
		* @default false
		* @private
		*/
		private _onCompleteCalled: boolean = false;

		/** 
		* The context that the onCompleteCallback should have when called.
		* @property _onCompleteContext
		* @type any
		* @default null
		* @private
		*/
		private _onCompleteContext: any = null;

		/**
		* An indication of whether or not this tween is currently running.
		* @property isRunning.
		* @type boolean
		* @default false
		* @public
		*/
		public isRunning: boolean = false;

		/** 
		* Sets up the various properties that define this tween.
		* The ending position/properties for this tween, how long the tween should go for, easing method to use and if should start right way.
		*
		* @method to
		* @param properties {Object} The ending location of the properties that you want to tween. 
		* @param [duration=1000] {Number} The duration of the tween.
		* @param [ease=null] {Any} The easing method to be used. If not specifed then this will default to LINEAR.
		* @param [autoStart=false] {boolean} If the tween should start right away.
		* @return {Kiwi.Animations.Tween}
		* @public
		*/
		public to(properties, duration: number = 1000, ease: any = null, autoStart: boolean = false):Tween {

			this._duration = duration;

			//  If properties isn't an object this will fail, sanity check it here somehow?
			this._valuesEnd = properties;

			if (ease !== null) {
				this._easingFunction = ease;
			}

			if (autoStart === true) {
				return this.start();

			} else {
				return this;
			}

		}

		/** 
		* Gets the initial values for the properties that it is to animate and starts the tween process.
		* @method start
		* @public
		*/
		public start() {
			var property;

			if (this._game === null || this._object === null)
			{
				return;
			}

			this.isRunning = true;

			this._manager.add(this);

			this._onStartCallbackFired = false;

			this._onCompleteCalled = false;

			this._startTime = this._manager.clock.elapsed() * 1000 + this._delayTime;

			for ( var property in this._valuesEnd ) {
				// This prevents the interpolation of null values or of non-existing properties
				if ( this._object[ property ] === null || !( property in this._object ) ) {
					continue;
				}

				// check if an Array was provided as property value
				if ( this._valuesEnd[ property ] instanceof Array ) {
					if ( this._valuesEnd[ property ].length === 0 ) {
						continue;
					}

					// create a local copy of the Array with the start value at the front
					this._valuesEnd[ property ] = [ this._object[ property ] ].concat(this._valuesEnd[ property ]);
				}

				//  Check if property is a function
				if ( typeof this._object[ property ] === "function" ) {
					this._valuesStart[ property ] = this._object[ property ]();
				} else {
					this._valuesStart[ property ] = this._object[ property ];
				}

			}

			return this;

		}

		/** 
		* Stops the Tween from running and removes it from the manager.
		* @method stop
		* @public
		*/
		public stop() {

			if (this._manager !== null)
			{
				this._manager.remove(this);
			}

			this.isRunning = false;

			return this;

		}

		/** 
		* Sets the game and the manager of this tween.
		* @method setParent
		* @param {Kiwi.Game} value
		* @public
		*/
		public setParent(value:Kiwi.Game) {

			this._game = value;
			this._manager = this._game.tweens;

		}

		/** 
		* Sets the amount of delay that the tween is to have before it starts playing.
		* @method delay
		* @param amount {Number} The amount of time to delay the tween by.
		* @return {Kiwi.Animations.Tween}
		* @public
		*/
		public delay(amount:number):Tween {

			this._delayTime = amount;
			return this;

		}

		/** 
		* Sets the easing method that is to be used when animating this tween.
		* @method easing
		* @param easing {Function} The easing function to use.
		* @return {Kiwi.Animations.Tween} 
		* @public
		*/
		public easing(easing):Tween {

			this._easingFunction = easing;
			return this;

		}

		/** 
		* [REQUIRES DESCRIPTION]
		* @method interpolation
		* @param {Any} interpolation
		* @return {Kiwi.Animations.Tween}
		* @public
		*/
		public interpolation(interpolation):Tween {

			this._interpolationFunction = interpolation;

			return this;

		}

		/** 
		* Adds another tween that should start playing once tween has completed.
		* @method chain
		* @param tween {Kiwi.Animations.Tween}
		* @return {Kiwi.Animations.Tween}
		* @public
		*/
		public chain(tween:Kiwi.Animations.Tween):Tween {

			this._chainedTweens.push(tween);
			return this;

		}

		/** 
		* Adds a function that is to be executed when the tween start playing.
		* @method onStart
		* @param callback {Function} The function that is to be executed on tween start.
		* @param context {any} The context that function is to have when called.
		* @return {Kiwi.Animations.Tween}
		* @public
		*/
		public onStart(callback, context):Tween {

			this._onStartCallback = callback;
			this._onStartContext = context;
			return this;

		}

		/** 
		* Adds a function that is to be executed when this tween updates while it is playing.
		* @method onUpdate
		* @param callback {Function} The method that is to be executed.
		* @param context {Any} The context the method is to have when called.
		* @public
		*/
		public onUpdate(callback, context) {

			this._onUpdateCallback = callback;
			this._onUpdateContext = context;
			return this;

		}

		/** 
		* Defines a method that is to be called when this tween is finished.
		* @method onComplete
		* @param callback {Function} The method that is to be executed.
		* @param context {Any} The context the method is to have when called.
		* @public
		*/
		public onComplete(callback, context) {

			this._onCompleteCallback = callback;
			this._onCompleteContext = context;

			return this;

		}

		/** 
		* The update loop is executed every frame whilst the tween is running.
		* @method update
		* @param time {Number}
		* @return {boolean} Whether the Tween is still running
		* @public
		*/
		public update( time: number ) {

			if ( time < this._startTime - this._delayTime ) {
				return false;
			}

			if ( this._onStartCallbackFired === false ) {
				if ( this._onStartCallback !== null ) {
					this._onStartCallback.call( this._onStartContext,
						this._object );
				}

				this._onStartCallbackFired = true;
			}

			var elapsed = ( time - this._startTime ) / this._duration;
			elapsed = elapsed > 1 ? 1 :
				elapsed < 0 ? 0 :
				elapsed;

			var value = this._easingFunction( elapsed );

			for ( var property in this._valuesStart ) {
				var start = this._valuesStart[ property ];
				var end = this._valuesEnd[ property ];

				//  Add checks for object, array, numeric up front
				if ( end instanceof Array ) {
					this._object[ property ] =
						this._interpolationFunction( end, value );
				} else {
					if ( typeof this._object[ property ] === "function" ) {
						this._object[ property ]( start + ( end - start ) * value );
					} else {
						this._object[ property ] = start + ( end - start ) * value;
					}
				}
			}

			if ( this._onUpdateCallback !== null ) {
				this._onUpdateCallback.call( this._onUpdateContext,
					this._object, value );
			}

			if ( elapsed === 1 ) {
				this.isRunning = false;

				if ( this._onCompleteCallback !== null &&
						this._onCompleteCalled === false ) {
					this._onCompleteCalled = true;
					this._onCompleteCallback.call(
						this._onCompleteContext, this._object );
				}

				for ( var i = 0; i < this._chainedTweens.length; i++ ) {
					this._chainedTweens[ i ].start();
				}

				return false;
			}

			return true;

		}

	}
}