/*
* Tween
* Visit http://createjs.com/ for documentation, updates and examples.
*
* Copyright (c) 2010 gskinner.com, inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* The TweenJS Javascript library provides a simple but powerful tweening interface. It supports tweening of both
* numeric object properties & CSS style properties, and allows you to chain tweens and actions together to create
* complex sequences.
*
* <h4>Simple Tween</h4>
* This tween will tween the target's alpha property from 0 to 1 for 1000ms (1 second) then call the <code>handleComplete</code> function.
*
* target.alpha = 0;
* createjs.Tween.get(target).to({alpha:1}, 1000).call(handleComplete);
* function handleComplete() {
* //Tween complete
* }
*
* <strong>Arguments and Scope</strong>
* Tween also supports a `call()` with arguments and/or a scope. If no scope is passed, then the function is called
* anonymously (normal JavaScript behaviour). The scope is useful for maintaining scope when doing object-oriented
* style development.
*
* createjs.Tween.get(target).to({alpha:0})
* .call(handleComplete, [argument1, argument2], this);
*
* <h4>Chainable Tween</h4>
* This tween will wait 0.5s, tween the target's alpha property to 0 over 1s, set it's visible to false, then call the
* <code>handleComplete</code> function.
*
* target.alpha = 1;
* createjs.Tween.get(target).wait(500).to({alpha:0, visible:false}, 1000).call(handleComplete);
* function handleComplete() {
* //Tween complete
* }
*
* <h4>Browser Support</h4>
* TweenJS will work in all browsers.
*
* @module TweenJS
* @main TweenJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
// constructor
/**
* Tweens properties for a single target. Methods can be chained to create complex animation sequences:
*
* <h4>Example</h4>
*
* createjs.Tween.get(target)
* .wait(500)
* .to({alpha:0, visible:false}, 1000)
* .call(handleComplete);
*
* Multiple tweens can share a target, however if they affect the same properties there could be unexpected
* behaviour. To stop all tweens on an object, use {{#crossLink "Tween/removeTweens"}}{{/crossLink}} or pass `override:true`
* in the props argument.
*
* createjs.Tween.get(target, {override:true}).to({x:100});
*
* Subscribe to the {{#crossLink "Tween/change:event"}}{{/crossLink}} event to be notified when the tween position changes.
*
* createjs.Tween.get(target, {override:true}).to({x:100}).addEventListener("change", handleChange);
* function handleChange(event) {
* // The tween changed.
* }
*
* See the {{#crossLink "Tween/get"}}{{/crossLink}} method also.
* @class Tween
* @param {Object} target The target object that will have its properties tweened.
* @param {Object} [props] The configuration properties to apply to this instance (ex. `{loop:-1, paused:true}`).
* Supported props are listed below. These props are set on the corresponding instance properties except where
* specified.
* @param {boolean} [props.useTicks=false] See the {{#crossLink "AbstractTween/useTicks:property"}}{{/crossLink}} property for more information.
* @param {boolean} [props.ignoreGlobalPause=false] See the {{#crossLink "AbstractTween/ignoreGlobalPause:property"}}{{/crossLink}} for more information.
* @param {number|boolean} [props.loop=0] See the {{#crossLink "AbstractTween/loop:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.reversed=false] See the {{#crossLink "AbstractTween/reversed:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.bounce=false] See the {{#crossLink "AbstractTween/bounce:property"}}{{/crossLink}} for more information.
* @param {number} [props.timeScale=1] See the {{#crossLink "AbstractTween/timeScale:property"}}{{/crossLink}} for more information.
* @param {object} [props.pluginData] See the {{#crossLink "Tween/pluginData:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.paused=false] See the {{#crossLink "AbstractTween/paused:property"}}{{/crossLink}} for more information.
* @param {number} [props.position=0] The initial position for this tween. See {{#crossLink "AbstractTween/position:property"}}{{/crossLink}}
* @param {Function} [props.onChange] Adds the specified function as a listener to the {{#crossLink "AbstractTween/change:event"}}{{/crossLink}} event
* @param {Function} [props.onComplete] Adds the specified function as a listener to the {{#crossLink "AbstractTween/complete:event"}}{{/crossLink}} event
* @param {boolean} [props.override=false] Removes all existing tweens for the target when set to `true`.
* @extends AbstractTween
* @constructor
*/
function Tween(target, props) {
this.AbstractTween_constructor(props);
// public properties:
/**
* Allows you to specify data that will be used by installed plugins. Each plugin uses this differently, but in general
* you specify data by assigning it to a property of `pluginData` with the same name as the plugin.
* Note that in many cases, this data is used as soon as the plugin initializes itself for the tween.
* As such, this data should be set before the first `to` call in most cases.
* @example
* myTween.pluginData.SmartRotation = data;
*
* Most plugins also support a property to disable them for a specific tween. This is typically the plugin name followed by "_disabled".
* @example
* myTween.pluginData.SmartRotation_disabled = true;
*
* Some plugins also store working data in this object, usually in a property named `_PluginClassName`.
* See the documentation for individual plugins for more details.
* @property pluginData
* @type {Object}
*/
this.pluginData = null;
/**
* The target of this tween. This is the object on which the tweened properties will be changed.
* @property target
* @type {Object}
* @readonly
*/
this.target = target;
/**
* Indicates the tween's current position is within a passive wait.
* @property passive
* @type {Boolean}
* @default false
* @readonly
**/
this.passive = false;
// private properties:
/**
* @property _stepHead
* @type {TweenStep}
* @protected
*/
this._stepHead = new TweenStep(null, 0, 0, {}, null, true);
/**
* @property _stepTail
* @type {TweenStep}
* @protected
*/
this._stepTail = this._stepHead;
/**
* The position within the current step. Used by MovieClip.
* @property _stepPosition
* @type {Number}
* @default 0
* @protected
*/
this._stepPosition = 0;
/**
* @property _actionHead
* @type {TweenAction}
* @protected
*/
this._actionHead = null;
/**
* @property _actionTail
* @type {TweenAction}
* @protected
*/
this._actionTail = null;
/**
* Plugins added to this tween instance.
* @property _plugins
* @type Array[Object]
* @default null
* @protected
*/
this._plugins = null;
/**
* Hash for quickly looking up added plugins. Null until a plugin is added.
* @property _plugins
* @type Object
* @default null
* @protected
*/
this._pluginIds = null;
/**
* Used by plugins to inject new properties.
* @property _injected
* @type {Object}
* @default null
* @protected
*/
this._injected = null;
if (props) {
this.pluginData = props.pluginData;
if (props.override) { Tween.removeTweens(target); }
}
if (!this.pluginData) { this.pluginData = {}; }
this._init(props);
}
var p = createjs.extend(Tween, createjs.AbstractTween);
// static properties
/**
* Constant returned by plugins to tell the tween not to use default assignment.
* @property IGNORE
* @type Object
* @static
*/
Tween.IGNORE = {};
/**
* @property _listeners
* @type Array[Tween]
* @static
* @protected
*/
Tween._tweens = [];
/**
* @property _plugins
* @type Object
* @static
* @protected
*/
Tween._plugins = null;
/**
* @property _tweenHead
* @type Tween
* @static
* @protected
*/
Tween._tweenHead = null;
/**
* @property _tweenTail
* @type Tween
* @static
* @protected
*/
Tween._tweenTail = null;
// static methods
/**
* Returns a new tween instance. This is functionally identical to using `new Tween(...)`, but may look cleaner
* with the chained syntax of TweenJS.
* <h4>Example</h4>
*
* var tween = createjs.Tween.get(target).to({x:100}, 500);
* // equivalent to:
* var tween = new createjs.Tween(target).to({x:100}, 500);
*
* @method get
* @param {Object} target The target object that will have its properties tweened.
* @param {Object} [props] The configuration properties to apply to this instance (ex. `{loop:-1, paused:true}`).
* Supported props are listed below. These props are set on the corresponding instance properties except where
* specified.
* @param {boolean} [props.useTicks=false] See the {{#crossLink "AbstractTween/useTicks:property"}}{{/crossLink}} property for more information.
* @param {boolean} [props.ignoreGlobalPause=false] See the {{#crossLink "AbstractTween/ignoreGlobalPause:property"}}{{/crossLink}} for more information.
* @param {number|boolean} [props.loop=0] See the {{#crossLink "AbstractTween/loop:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.reversed=false] See the {{#crossLink "AbstractTween/reversed:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.bounce=false] See the {{#crossLink "AbstractTween/bounce:property"}}{{/crossLink}} for more information.
* @param {number} [props.timeScale=1] See the {{#crossLink "AbstractTween/timeScale:property"}}{{/crossLink}} for more information.
* @param {object} [props.pluginData] See the {{#crossLink "Tween/pluginData:property"}}{{/crossLink}} for more information.
* @param {boolean} [props.paused=false] See the {{#crossLink "AbstractTween/paused:property"}}{{/crossLink}} for more information.
* @param {number} [props.position=0] The initial position for this tween. See {{#crossLink "AbstractTween/position:property"}}{{/crossLink}}
* @param {Function} [props.onChange] Adds the specified function as a listener to the {{#crossLink "AbstractTween/change:event"}}{{/crossLink}} event
* @param {Function} [props.onComplete] Adds the specified function as a listener to the {{#crossLink "AbstractTween/complete:event"}}{{/crossLink}} event
* @param {boolean} [props.override=false] Removes all existing tweens for the target when set to `true`.
* @return {Tween} A reference to the created tween.
* @static
*/
Tween.get = function(target, props) {
return new Tween(target, props);
};
/**
* Advances all tweens. This typically uses the {{#crossLink "Ticker"}}{{/crossLink}} class, but you can call it
* manually if you prefer to use your own "heartbeat" implementation.
* @method tick
* @param {Number} delta The change in time in milliseconds since the last tick. Required unless all tweens have
* `useTicks` set to true.
* @param {Boolean} paused Indicates whether a global pause is in effect. Tweens with {{#crossLink "Tween/ignoreGlobalPause:property"}}{{/crossLink}}
* will ignore this, but all others will pause if this is `true`.
* @static
*/
Tween.tick = function(delta, paused) {
var tween = Tween._tweenHead;
while (tween) {
var next = tween._next; // in case it completes and wipes its _next property
if ((paused && !tween.ignoreGlobalPause) || tween._paused) { /* paused */ }
else { tween.advance(tween.useTicks?1:delta); }
tween = next;
}
};
/**
* Handle events that result from Tween being used as an event handler. This is included to allow Tween to handle
* {{#crossLink "Ticker/tick:event"}}{{/crossLink}} events from the createjs {{#crossLink "Ticker"}}{{/crossLink}}.
* No other events are handled in Tween.
* @method handleEvent
* @param {Object} event An event object passed in by the {{#crossLink "EventDispatcher"}}{{/crossLink}}. Will
* usually be of type "tick".
* @private
* @static
* @since 0.4.2
*/
Tween.handleEvent = function(event) {
if (event.type === "tick") {
this.tick(event.delta, event.paused);
}
};
/**
* Removes all existing tweens for a target. This is called automatically by new tweens if the `override`
* property is `true`.
* @method removeTweens
* @param {Object} target The target object to remove existing tweens from.
* @static
*/
Tween.removeTweens = function(target) {
if (!target.tweenjs_count) { return; }
var tween = Tween._tweenHead;
while (tween) {
var next = tween._next;
if (tween.target === target) { Tween._register(tween, true); }
tween = next;
}
target.tweenjs_count = 0;
};
/**
* Stop and remove all existing tweens.
* @method removeAllTweens
* @static
* @since 0.4.1
*/
Tween.removeAllTweens = function() {
var tween = Tween._tweenHead;
while (tween) {
var next = tween._next;
tween._paused = true;
tween.target&&(tween.target.tweenjs_count = 0);
tween._next = tween._prev = null;
tween = next;
}
Tween._tweenHead = Tween._tweenTail = null;
};
/**
* Indicates whether there are any active tweens on the target object (if specified) or in general.
* @method hasActiveTweens
* @param {Object} [target] The target to check for active tweens. If not specified, the return value will indicate
* if there are any active tweens on any target.
* @return {Boolean} Indicates if there are active tweens.
* @static
*/
Tween.hasActiveTweens = function(target) {
if (target) { return !!target.tweenjs_count; }
return !!Tween._tweenHead;
};
/**
* Installs a plugin, which can modify how certain properties are handled when tweened. See the {{#crossLink "SamplePlugin"}}{{/crossLink}}
* for an example of how to write TweenJS plugins. Plugins should generally be installed via their own `install` method, in order to provide
* the plugin with an opportunity to configure itself.
* @method _installPlugin
* @param {Object} plugin The plugin to install
* @static
* @protected
*/
Tween._installPlugin = function(plugin) {
var priority = (plugin.priority = plugin.priority||0), arr = (Tween._plugins = Tween._plugins || []);
for (var i=0,l=arr.length;i<l;i++) {
if (priority < arr[i].priority) { break; }
}
arr.splice(i,0,plugin);
};
/**
* Registers or unregisters a tween with the ticking system.
* @method _register
* @param {Tween} tween The tween instance to register or unregister.
* @param {Boolean} paused If `false`, the tween is registered. If `true` the tween is unregistered.
* @static
* @protected
*/
Tween._register = function(tween, paused) {
var target = tween.target;
if (!paused && tween._paused) {
// TODO: this approach might fail if a dev is using sealed objects
if (target) { target.tweenjs_count = target.tweenjs_count ? target.tweenjs_count+1 : 1; }
var tail = Tween._tweenTail;
if (!tail) { Tween._tweenHead = Tween._tweenTail = tween; }
else {
Tween._tweenTail = tail._next = tween;
tween._prev = tail;
}
if (!Tween._inited && createjs.Ticker) { createjs.Ticker.addEventListener("tick", Tween); Tween._inited = true; }
} else if (paused && !tween._paused) {
if (target) { target.tweenjs_count--; }
var next = tween._next, prev = tween._prev;
if (next) { next._prev = prev; }
else { Tween._tweenTail = prev; } // was tail
if (prev) { prev._next = next; }
else { Tween._tweenHead = next; } // was head.
tween._next = tween._prev = null;
}
tween._paused = paused;
};
// events:
// public methods:
/**
* Adds a wait (essentially an empty tween).
* <h4>Example</h4>
*
* //This tween will wait 1s before alpha is faded to 0.
* createjs.Tween.get(target).wait(1000).to({alpha:0}, 1000);
*
* @method wait
* @param {Number} duration The duration of the wait in milliseconds (or in ticks if `useTicks` is true).
* @param {Boolean} [passive=false] Tween properties will not be updated during a passive wait. This
* is mostly useful for use with {{#crossLink "Timeline"}}{{/crossLink}} instances that contain multiple tweens
* affecting the same target at different times.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
**/
p.wait = function(duration, passive) {
if (duration > 0) { this._addStep(+duration, this._stepTail.props, null, passive); }
return this;
};
/**
* Adds a tween from the current values to the specified properties. Set duration to 0 to jump to these value.
* Numeric properties will be tweened from their current value in the tween to the target value. Non-numeric
* properties will be set at the end of the specified duration.
* <h4>Example</h4>
*
* createjs.Tween.get(target).to({alpha:0, visible:false}, 1000);
*
* @method to
* @param {Object} props An object specifying property target values for this tween (Ex. `{x:300}` would tween the x
* property of the target to 300).
* @param {Number} [duration=0] The duration of the tween in milliseconds (or in ticks if `useTicks` is true).
* @param {Function} [ease="linear"] The easing function to use for this tween. See the {{#crossLink "Ease"}}{{/crossLink}}
* class for a list of built-in ease functions.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
*/
p.to = function(props, duration, ease) {
if (duration == null || duration < 0) { duration = 0; }
var step = this._addStep(+duration, null, ease);
this._appendProps(props, step);
return this;
};
/**
* Adds a label that can be used with {{#crossLink "Tween/gotoAndPlay"}}{{/crossLink}}/{{#crossLink "Tween/gotoAndStop"}}{{/crossLink}}
* at the current point in the tween. For example:
*
* var tween = createjs.Tween.get(foo)
* .to({x:100}, 1000)
* .label("myLabel")
* .to({x:200}, 1000);
* // ...
* tween.gotoAndPlay("myLabel"); // would play from 1000ms in.
*
* @method label
* @param {String} name The label name.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
**/
p.label = function(name) {
this.addLabel(name, this.duration);
return this;
};
/**
* Adds an action to call the specified function.
* <h4>Example</h4>
*
* //would call myFunction() after 1 second.
* createjs.Tween.get().wait(1000).call(myFunction);
*
* @method call
* @param {Function} callback The function to call.
* @param {Array} [params]. The parameters to call the function with. If this is omitted, then the function
* will be called with a single param pointing to this tween.
* @param {Object} [scope]. The scope to call the function in. If omitted, it will be called in the target's scope.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
*/
p.call = function(callback, params, scope) {
return this._addAction(scope||this.target, callback, params||[this]);
};
/**
* Adds an action to set the specified props on the specified target. If `target` is null, it will use this tween's
* target. Note that for properties on the target object, you should consider using a zero duration {{#crossLink "Tween/to"}}{{/crossLink}}
* operation instead so the values are registered as tweened props.
* <h4>Example</h4>
*
* myTween.wait(1000).set({visible:false}, foo);
*
* @method set
* @param {Object} props The properties to set (ex. `{visible:false}`).
* @param {Object} [target] The target to set the properties on. If omitted, they will be set on the tween's target.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
*/
p.set = function(props, target) {
return this._addAction(target||this.target, this._set, [props]);
};
/**
* Adds an action to play (unpause) the specified tween. This enables you to sequence multiple tweens.
* <h4>Example</h4>
*
* myTween.to({x:100}, 500).play(otherTween);
*
* @method play
* @param {Tween} [tween] The tween to play. Defaults to this tween.
* @return {Tween} This tween instance (for chaining calls).
* @chainable
*/
p.play = function(tween) {
return this._addAction(tween||this, this._set, [{paused:false}]);
};
/**
* Adds an action to pause the specified tween.
*
* myTween.pause(otherTween).to({alpha:1}, 1000).play(otherTween);
*
* Note that this executes at the end of a tween update, so the tween may advance beyond the time the pause
* action was inserted at. For example:
*
* myTween.to({foo:0}, 1000).pause().to({foo:1}, 1000);
*
* At 60fps the tween will advance by ~16ms per tick, if the tween above was at 999ms prior to the current tick, it
* will advance to 1015ms (15ms into the second "step") and then pause.
*
* @method pause
* @param {Tween} [tween] The tween to pause. Defaults to this tween.
* @return {Tween} This tween instance (for chaining calls)
* @chainable
*/
p.pause = function(tween) {
return this._addAction(tween||this, this._set, [{paused:true}]);
};
// tiny api (primarily for tool output):
p.w = p.wait;
p.t = p.to;
p.c = p.call;
p.s = p.set;
/**
* Returns a string representation of this object.
* @method toString
* @return {String} a string representation of the instance.
*/
p.toString = function() {
return "[Tween]";
};
/**
* @method clone
* @protected
*/
p.clone = function() {
throw("Tween can not be cloned.")
};
// private methods:
/**
* Adds a plugin to this tween.
* @method _addPlugin
* @param {Object} plugin
* @protected
*/
p._addPlugin = function(plugin) {
var ids = this._pluginIds || (this._pluginIds = {}), id = plugin.ID;
if (!id || ids[id]) { return; } // already added
ids[id] = true;
var plugins = this._plugins || (this._plugins = []), priority = plugin.priority || 0;
for (var i=0,l=plugins.length; i<l; i++) {
if (priority < plugins[i].priority) {
plugins.splice(i,0,plugin);
return;
}
}
plugins.push(plugin);
};
// Docced in AbstractTween
p._updatePosition = function(jump, end) {
var step = this._stepHead.next, t=this.position, d=this.duration;
if (this.target && step) {
// find our new step index:
var stepNext = step.next;
while (stepNext && stepNext.t <= t) { step = step.next; stepNext = step.next; }
var ratio = end ? d === 0 ? 1 : t/d : (t-step.t)/step.d; // TODO: revisit this.
this._updateTargetProps(step, ratio, end);
}
this._stepPosition = step ? t-step.t : 0;
};
/**
* @method _updateTargetProps
* @param {Object} step
* @param {Number} ratio
* @param {Boolean} end Indicates to plugins that the full tween has ended.
* @protected
*/
p._updateTargetProps = function(step, ratio, end) {
if (this.passive = !!step.passive) { return; } // don't update props.
var v, v0, v1, ease;
var p0 = step.prev.props;
var p1 = step.props;
if (ease = step.ease) { ratio = ease(ratio,0,1,1); }
var plugins = this._plugins;
proploop : for (var n in p0) {
v0 = p0[n];
v1 = p1[n];
// values are different & it is numeric then interpolate:
if (v0 !== v1 && (typeof(v0) === "number")) {
v = v0+(v1-v0)*ratio;
} else {
v = ratio >= 1 ? v1 : v0;
}
if (plugins) {
for (var i=0,l=plugins.length;i<l;i++) {
var value = plugins[i].change(this, step, n, v, ratio, end);
if (value === Tween.IGNORE) { continue proploop; }
if (value !== undefined) { v = value; }
}
}
this.target[n] = v;
}
};
/**
* @method _runActionsRange
* @param {Number} startPos
* @param {Number} endPos
* @param {Boolean} jump
* @param {Boolean} includeStart
* @protected
*/
p._runActionsRange = function(startPos, endPos, jump, includeStart) {
var rev = startPos > endPos;
var action = rev ? this._actionTail : this._actionHead;
var ePos = endPos, sPos = startPos;
if (rev) { ePos=startPos; sPos=endPos; }
var t = this.position;
while (action) {
var pos = action.t;
if (pos === endPos || (pos > sPos && pos < ePos) || (includeStart && pos === startPos)) {
action.funct.apply(action.scope, action.params);
if (t !== this.position) { return true; }
}
action = rev ? action.prev : action.next;
}
};
/**
* @method _appendProps
* @param {Object} props
* @param {Object} step
* @param {Array} stepPlugins
* @protected
*/
p._appendProps = function(props, step, stepPlugins) {
var initProps = this._stepHead.props, target = this.target, plugins = Tween._plugins;
var n, i, value, initValue, inject;
var oldStep = step.prev, oldProps = oldStep.props;
var stepProps = step.props || (step.props = this._cloneProps(oldProps));
var cleanProps = {}; // TODO: is there some way to avoid this additional object?
for (n in props) {
if (!props.hasOwnProperty(n)) { continue; }
cleanProps[n] = stepProps[n] = props[n];
if (initProps[n] !== undefined) { continue; }
initValue = undefined; // accessing missing properties on DOMElements when using CSSPlugin is INSANELY expensive, so we let the plugin take a first swing at it.
if (plugins) {
for (i = plugins.length-1; i >= 0; i--) {
value = plugins[i].init(this, n, initValue);
if (value !== undefined) { initValue = value; }
if (initValue === Tween.IGNORE) {
delete(stepProps[n]);
delete(cleanProps[n]);
break;
}
}
}
if (initValue !== Tween.IGNORE) {
if (initValue === undefined) { initValue = target[n]; }
oldProps[n] = (initValue === undefined) ? null : initValue;
}
}
for (n in cleanProps) {
value = props[n];
// propagate old value to previous steps:
var o, prev=oldStep;
while ((o = prev) && (prev = o.prev)) {
if (prev.props === o.props) { continue; } // wait step
if (prev.props[n] !== undefined) { break; } // already has a value, we're done.
prev.props[n] = oldProps[n];
}
}
if (stepPlugins !== false && (plugins = this._plugins)) {
for (i = plugins.length-1; i >= 0; i--) {
plugins[i].step(this, step, cleanProps);
}
}
if (inject = this._injected) {
this._injected = null;
this._appendProps(inject, step, false);
}
};
/**
* Used by plugins to inject properties onto the current step. Called from within `Plugin.step` calls.
* For example, a plugin dealing with color, could read a hex color, and inject red, green, and blue props into the tween.
* See the SamplePlugin for more info.
* @method _injectProp
* @param {String} name
* @param {Object} value
* @protected
*/
p._injectProp = function(name, value) {
var o = this._injected || (this._injected = {});
o[name] = value;
};
/**
* @method _addStep
* @param {Number} duration
* @param {Object} props
* @param {Function} ease
* @param {Boolean} passive
* @protected
*/
p._addStep = function(duration, props, ease, passive) {
var step = new TweenStep(this._stepTail, this.duration, duration, props, ease, passive||false);
this.duration += duration;
return this._stepTail = (this._stepTail.next = step);
};
/**
* @method _addAction
* @param {Object} scope
* @param {Function} funct
* @param {Array} params
* @protected
*/
p._addAction = function(scope, funct, params) {
var action = new TweenAction(this._actionTail, this.duration, scope, funct, params);
if (this._actionTail) { this._actionTail.next = action; }
else { this._actionHead = action; }
this._actionTail = action;
return this;
};
/**
* @method _set
* @param {Object} props
* @protected
*/
p._set = function(props) {
for (var n in props) {
this[n] = props[n];
}
};
/**
* @method _cloneProps
* @param {Object} props
* @protected
*/
p._cloneProps = function(props) {
var o = {};
for (var n in props) { o[n] = props[n]; }
return o;
};
createjs.Tween = createjs.promote(Tween, "AbstractTween");
function TweenStep(prev, t, d, props, ease, passive) {
this.next = null;
this.prev = prev;
this.t = t;
this.d = d;
this.props = props;
this.ease = ease;
this.passive = passive;
this.index = prev ? prev.index+1 : 0;
}
function TweenAction(prev, t, scope, funct, params) {
this.next = null;
this.prev = prev;
this.t = t;
this.d = 0;
this.scope = scope;
this.funct = funct;
this.params = params;
}
}());