lettuce
Version:
Lettuce JS, Mini Mobile Framework for Romantic with DSL.
862 lines (625 loc) • 23 kB
JavaScript
/**
* @preserve Tween JS
* https://github.com/sole/Tween.js
*/
/* jshint -W011 */
/* jshint -W013 */
/* jshint -W089 */
/* jshint -W093 */
/* jshint -W098 */
/* jshint -W108 */
/* jshint -W116 */
(function() {
/**
* Javascript Tweening Engine<p>
* Super simple, fast and easy to use tweening engine which incorporates optimised Robert Penner's equation<p>
* <a href="https://github.com/sole/Tween.js">https://github.com/sole/Tween.js</a><p>
* author sole / http://soledadpenades.com<br>
* author mr.doob / http://mrdoob.com<br>
* author Robert Eisele / http://www.xarg.org<br>
* author Philippe / http://philippe.elsass.me<br>
* author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html<br>
* author Paul Lewis / http://www.aerotwist.com/<br>
* author lechecacharro<br>
* author Josh Faul / http://jocafa.com/
* @class
* @memberOf me
* @constructor
* @param {Object} object object on which to apply the tween
* @example
* // add a tween to change the object pos.y variable to 200 in 3 seconds
* tween = new me.Tween(myObject.pos).to({y: 200}, 3000).onComplete(myFunc);
* tween.easing(me.Tween.Easing.Bounce.Out);
* tween.start();
*/
me.Tween = function ( object ) {
var _object = object;
var _valuesStart = {};
var _valuesEnd = {};
var _valuesStartRepeat = {};
var _duration = 1000;
var _repeat = 0;
var _yoyo = false;
var _reversed = false;
var _delayTime = 0;
var _startTime = null;
var _easingFunction = me.Tween.Easing.Linear.None;
var _interpolationFunction = me.Tween.Interpolation.Linear;
var _chainedTweens = [];
var _onStartCallback = null;
var _onStartCallbackFired = false;
var _onUpdateCallback = null;
var _onCompleteCallback = null;
// Set all starting values present on the target object
for ( var field in object ) {
if(typeof object !== 'object') {
_valuesStart[ field ] = parseFloat(object[field], 10);
}
}
/**
* reset the tween object to default value
* @ignore
*/
this.onResetEvent = function ( object ) {
_object = object;
_valuesStart = {};
_valuesEnd = {};
_valuesStartRepeat = {};
_easingFunction = me.Tween.Easing.Linear.None;
_interpolationFunction = me.Tween.Interpolation.Linear;
_yoyo = false;
_reversed = false;
_duration = 1000;
_delayTime = 0;
_onStartCallback = null;
_onStartCallbackFired = false;
_onUpdateCallback = null;
_onCompleteCallback = null;
};
/**
* object properties to be updated and duration
* @name me.Tween#to
* @public
* @function
* @param {Object} properties hash of properties
* @param {Number} [duration=1000] tween duration
*/
this.to = function ( properties, duration ) {
if ( duration !== undefined ) {
_duration = duration;
}
_valuesEnd = properties;
return this;
};
/**
* start the tween
* @name me.Tween#start
* @public
* @function
*/
this.start = function ( time ) {
_onStartCallbackFired = false;
// add the tween to the object pool on start
me.game.world.addChild(this);
_startTime = (typeof(time) === 'undefined' ? me.timer.getTime() : time) + _delayTime;
for ( var property in _valuesEnd ) {
// check if an Array was provided as property value
if ( _valuesEnd[ property ] instanceof Array ) {
if ( _valuesEnd[ property ].length === 0 ) {
continue;
}
// create a local copy of the Array with the start value at the front
_valuesEnd[ property ] = [ _object[ property ] ].concat( _valuesEnd[ property ] );
}
_valuesStart[ property ] = _object[ property ];
if( ( _valuesStart[ property ] instanceof Array ) === false ) {
_valuesStart[ property ] *= 1.0; // Ensures we're using numbers, not strings
}
_valuesStartRepeat[ property ] = _valuesStart[ property ] || 0;
}
return this;
};
/**
* stop the tween
* @name me.Tween#stop
* @public
* @function
*/
this.stop = function () {
// ensure the tween has not been removed previously
if (me.game.world.hasChild(this)) {
me.game.world.removeChildNow(this);
}
return this;
};
/**
* delay the tween
* @name me.Tween#delay
* @public
* @function
* @param {Number} amount delay amount expressed in milliseconds
*/
this.delay = function ( amount ) {
_delayTime = amount;
return this;
};
/**
* Calculate delta to resume the tween
* @ignore
*/
me.event.subscribe(me.event.STATE_RESUME, function onResume(elapsed) {
if (_startTime) {
_startTime += elapsed;
}
});
/**
* Repeat the tween
* @name me.Tween#repeat
* @public
* @function
* @param {Number} times amount of times the tween should be repeated
*/
this.repeat = function ( times ) {
_repeat = times;
return this;
};
/**
* allows the tween to bounce back to their original value when finished
* @name me.Tween#yoyo
* @public
* @function
* @param {Boolean} yoyo
*/
this.yoyo = function( yoyo ) {
_yoyo = yoyo;
return this;
};
/**
* set the easing function
* @name me.Tween#easing
* @public
* @function
* @param {me.Tween#Easing} easing easing function
*/
this.easing = function ( easing ) {
if (typeof easing !== 'function') {
throw new me.Tween.Error("invalid easing function for me.Tween.easing()");
}
_easingFunction = easing;
return this;
};
/**
* set the interpolation function
* @name me.Tween#interpolation
* @public
* @function
* @param {me.Tween#Interpolation} easing easing function
*/
this.interpolation = function ( interpolation ) {
_interpolationFunction = interpolation;
return this;
};
/**
* chain the tween
* @name me.Tween#chain
* @public
* @function
* @param {me.Tween} chainedTween Tween to be chained
*/
this.chain = function () {
_chainedTweens = arguments;
return this;
};
/**
* onStart callback
* @name me.Tween#onStart
* @public
* @function
* @param {Function} onStartCallback callback
*/
this.onStart = function ( callback ) {
_onStartCallback = callback;
return this;
};
/**
* onUpdate callback
* @name me.Tween#onUpdate
* @public
* @function
* @param {Function} onUpdateCallback callback
*/
this.onUpdate = function ( callback ) {
_onUpdateCallback = callback;
return this;
};
/**
* onComplete callback
* @name me.Tween#onComplete
* @public
* @function
* @param {Function} onCompleteCallback callback
*/
this.onComplete = function ( callback ) {
_onCompleteCallback = callback;
return this;
};
/** @ignore*/
this.update = function ( dt ) {
// the original Tween implementation expect
// a timestamp and not a time delta
var time = me.timer.getTime();
var property;
if ( time < _startTime ) {
return true;
}
if ( _onStartCallbackFired === false ) {
if ( _onStartCallback !== null ) {
_onStartCallback.call( _object );
}
_onStartCallbackFired = true;
}
var elapsed = ( time - _startTime ) / _duration;
elapsed = elapsed > 1 ? 1 : elapsed;
var value = _easingFunction( elapsed );
for ( property in _valuesEnd ) {
var start = _valuesStart[ property ] || 0;
var end = _valuesEnd[ property ];
if ( end instanceof Array ) {
_object[ property ] = _interpolationFunction( end, value );
} else {
// Parses relative end values with start as base (e.g.: +10, -3)
if ( typeof(end) === "string" ) {
end = start + parseFloat(end, 10);
}
// protect against non numeric properties.
if ( typeof(end) === "number" ) {
_object[ property ] = start + ( end - start ) * value;
}
}
}
if ( _onUpdateCallback !== null ) {
_onUpdateCallback.call( _object, value );
}
if ( elapsed === 1 ) {
if ( _repeat > 0 ) {
if( isFinite( _repeat ) ) {
_repeat--;
}
// reassign starting values, restart by making startTime = now
for( property in _valuesStartRepeat ) {
if ( typeof( _valuesEnd[ property ] ) === "string" ) {
_valuesStartRepeat[ property ] = _valuesStartRepeat[ property ] + parseFloat(_valuesEnd[ property ], 10);
}
if (_yoyo) {
var tmp = _valuesStartRepeat[ property ];
_valuesStartRepeat[ property ] = _valuesEnd[ property ];
_valuesEnd[ property ] = tmp;
}
_valuesStart[ property ] = _valuesStartRepeat[ property ];
}
if (_yoyo) {
_reversed = !_reversed;
}
_startTime = time + _delayTime;
return true;
} else {
// remove the tween from the object pool
me.game.world.removeChildNow(this);
if ( _onCompleteCallback !== null ) {
_onCompleteCallback.call( _object );
}
for ( var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i ++ ) {
_chainedTweens[ i ].start( time );
}
return false;
}
}
return true;
};
};
/**
* Easing Function :<br>
* <p>
* me.Tween.Easing.Linear.None<br>
* me.Tween.Easing.Quadratic.In<br>
* me.Tween.Easing.Quadratic.Out<br>
* me.Tween.Easing.Quadratic.InOut<br>
* me.Tween.Easing.Cubic.In<br>
* me.Tween.Easing.Cubic.Out<br>
* me.Tween.Easing.Cubic.InOut<br>
* me.Tween.Easing.Quartic.In<br>
* me.Tween.Easing.Quartic.Out<br>
* me.Tween.Easing.Quartic.InOut<br>
* me.Tween.Easing.Quintic.In<br>
* me.Tween.Easing.Quintic.Out<br>
* me.Tween.Easing.Quintic.InOut<br>
* me.Tween.Easing.Sinusoidal.In<br>
* me.Tween.Easing.Sinusoidal.Out<br>
* me.Tween.Easing.Sinusoidal.InOut<br>
* me.Tween.Easing.Exponential.In<br>
* me.Tween.Easing.Exponential.Out<br>
* me.Tween.Easing.Exponential.InOut<br>
* me.Tween.Easing.Circular.In<br>
* me.Tween.Easing.Circular.Out<br>
* me.Tween.Easing.Circular.InOut<br>
* me.Tween.Easing.Elastic.In<br>
* me.Tween.Easing.Elastic.Out<br>
* me.Tween.Easing.Elastic.InOut<br>
* me.Tween.Easing.Back.In<br>
* me.Tween.Easing.Back.Out<br>
* me.Tween.Easing.Back.InOut<br>
* me.Tween.Easing.Bounce.In<br>
* me.Tween.Easing.Bounce.Out<br>
* me.Tween.Easing.Bounce.InOut
* </p>
* @public
* @constant
* @type enum
* @name me.Tween#Easing
*/
me.Tween.Easing = {
Linear: {
/** @ignore */
None: function ( k ) {
return k;
}
},
Quadratic: {
/** @ignore */
In: function ( k ) {
return k * k;
},
/** @ignore */
Out: function ( k ) {
return k * ( 2 - k );
},
/** @ignore */
InOut: function ( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
return - 0.5 * ( --k * ( k - 2 ) - 1 );
}
},
Cubic: {
/** @ignore */
In: function ( k ) {
return k * k * k;
},
/** @ignore */
Out: function ( k ) {
return --k * k * k + 1;
},
/** @ignore */
InOut: function ( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
return 0.5 * ( ( k -= 2 ) * k * k + 2 );
}
},
Quartic: {
/** @ignore */
In: function ( k ) {
return k * k * k * k;
},
/** @ignore */
Out: function ( k ) {
return 1 - ( --k * k * k * k );
},
/** @ignore */
InOut: function ( k ) {
if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
}
},
Quintic: {
/** @ignore */
In: function ( k ) {
return k * k * k * k * k;
},
/** @ignore */
Out: function ( k ) {
return --k * k * k * k * k + 1;
},
/** @ignore */
InOut: function ( k ) {
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
}
},
Sinusoidal: {
/** @ignore */
In: function ( k ) {
return 1 - Math.cos( k * Math.PI / 2 );
},
/** @ignore */
Out: function ( k ) {
return Math.sin( k * Math.PI / 2 );
},
/** @ignore */
InOut: function ( k ) {
return 0.5 * ( 1 - Math.cos( Math.PI * k ) );
}
},
Exponential: {
/** @ignore */
In: function ( k ) {
return k === 0 ? 0 : Math.pow( 1024, k - 1 );
},
/** @ignore */
Out: function ( k ) {
return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k );
},
/** @ignore */
InOut: function ( k ) {
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 );
return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
}
},
Circular: {
/** @ignore */
In: function ( k ) {
return 1 - Math.sqrt( 1 - k * k );
},
/** @ignore */
Out: function ( k ) {
return Math.sqrt( 1 - ( --k * k ) );
},
/** @ignore */
InOut: function ( k ) {
if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
}
},
Elastic: {
/** @ignore */
In: function ( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
},
/** @ignore */
Out: function ( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
},
/** @ignore */
InOut: function ( k ) {
var s, a = 0.1, p = 0.4;
if ( k === 0 ) return 0;
if ( k === 1 ) return 1;
if ( !a || a < 1 ) { a = 1; s = p / 4; }
else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
}
},
Back: {
/** @ignore */
In: function ( k ) {
var s = 1.70158;
return k * k * ( ( s + 1 ) * k - s );
},
/** @ignore */
Out: function ( k ) {
var s = 1.70158;
return --k * k * ( ( s + 1 ) * k + s ) + 1;
},
/** @ignore */
InOut: function ( k ) {
var s = 1.70158 * 1.525;
if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
}
},
Bounce: {
/** @ignore */
In: function ( k ) {
return 1 - me.Tween.Easing.Bounce.Out( 1 - k );
},
/** @ignore */
Out: function ( k ) {
if ( k < ( 1 / 2.75 ) ) {
return 7.5625 * k * k;
} else if ( k < ( 2 / 2.75 ) ) {
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
} else if ( k < ( 2.5 / 2.75 ) ) {
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
} else {
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
}
},
/** @ignore */
InOut: function ( k ) {
if ( k < 0.5 ) return me.Tween.Easing.Bounce.In( k * 2 ) * 0.5;
return me.Tween.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5;
}
}
};
/* Interpolation Function :<br>
* <p>
* me.Tween.Interpolation.Linear<br>
* me.Tween.Interpolation.Bezier<br>
* me.Tween.Interpolation.CatmullRom<br>
* </p>
* @public
* @constant
* @type enum
* @name me.Tween#Interpolation
*/
me.Tween.Interpolation = {
/** @ignore */
Linear: function ( v, k ) {
var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = me.Tween.Interpolation.Utils.Linear;
if ( k < 0 ) return fn( v[ 0 ], v[ 1 ], f );
if ( k > 1 ) return fn( v[ m ], v[ m - 1 ], m - f );
return fn( v[ i ], v[ i + 1 > m ? m : i + 1 ], f - i );
},
/** @ignore */
Bezier: function ( v, k ) {
var b = 0, n = v.length - 1, pw = Math.pow, bn = me.Tween.Interpolation.Utils.Bernstein, i;
for ( i = 0; i <= n; i++ ) {
b += pw( 1 - k, n - i ) * pw( k, i ) * v[ i ] * bn( n, i );
}
return b;
},
/** @ignore */
CatmullRom: function ( v, k ) {
var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = me.Tween.Interpolation.Utils.CatmullRom;
if ( v[ 0 ] === v[ m ] ) {
if ( k < 0 ) i = Math.floor( f = m * ( 1 + k ) );
return fn( v[ ( i - 1 + m ) % m ], v[ i ], v[ ( i + 1 ) % m ], v[ ( i + 2 ) % m ], f - i );
} else {
if ( k < 0 ) return v[ 0 ] - ( fn( v[ 0 ], v[ 0 ], v[ 1 ], v[ 1 ], -f ) - v[ 0 ] );
if ( k > 1 ) return v[ m ] - ( fn( v[ m ], v[ m ], v[ m - 1 ], v[ m - 1 ], f - m ) - v[ m ] );
return fn( v[ i ? i - 1 : 0 ], v[ i ], v[ m < i + 1 ? m : i + 1 ], v[ m < i + 2 ? m : i + 2 ], f - i );
}
},
Utils: {
/** @ignore */
Linear: function ( p0, p1, t ) {
return ( p1 - p0 ) * t + p0;
},
/** @ignore */
Bernstein: function ( n , i ) {
var fc = me.Tween.Interpolation.Utils.Factorial;
return fc( n ) / fc( i ) / fc( n - i );
},
/** @ignore */
Factorial: ( function () {
var a = [ 1 ];
return function ( n ) {
var s = 1, i;
if ( a[ n ] ) return a[ n ];
for ( i = n; i > 1; i-- ) s *= i;
return a[ n ] = s;
};
} )(),
/** @ignore */
CatmullRom: function ( p0, p1, p2, p3, t ) {
var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5, t2 = t * t, t3 = t * t2;
return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
}
}
};
/**
* Base class for Tween exception handling.
* @name Error
* @class
* @memberOf me.Tween
* @constructor
* @param {String} msg Error message.
*/
me.Tween.Error = me.Error.extend({
init : function (msg) {
this._super(me.Error, "init", [ msg ]);
this.name = "me.Tween.Error";
}
});
})();