codecombat/vendor/scripts/tweenjs-NEXT.combined.js
Scott Erickson 4b3bfbb7e2 Fixed #317
2014-02-02 16:31:06 -08:00

2760 lines
83 KiB
JavaScript

/*
* Event
* 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.
*/
/**
* A collection of Classes that are shared across all the CreateJS libraries. The classes are included in the minified
* files of each library and are available on the createsjs namespace directly.
*
* <h4>Example</h4>
* myObject.addEventListener("change", createjs.proxy(myMethod, scope));
*
* @module CreateJS
* @main CreateJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* Contains properties and methods shared by all events for use with
* {{#crossLink "EventDispatcher"}}{{/crossLink}}.
*
* Note that Event objects are often reused, so you should never
* rely on an event object's state outside of the call stack it was received in.
* @class Event
* @param {String} type The event type.
* @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
* @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
* @constructor
**/
var Event = function(type, bubbles, cancelable) {
this.initialize(type, bubbles, cancelable);
};
var p = Event.prototype;
// events:
// public properties:
/**
* The type of event.
* @property type
* @type String
**/
p.type = null;
/**
* The object that generated an event.
* @property target
* @type Object
* @default null
* @readonly
*/
p.target = null;
/**
* The current target that a bubbling event is being dispatched from. For non-bubbling events, this will
* always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event
* is generated from childObj, then a listener on parentObj would receive the event with
* target=childObj (the original target) and currentTarget=parentObj (where the listener was added).
* @property currentTarget
* @type Object
* @default null
* @readonly
*/
p.currentTarget = null;
/**
* For bubbling events, this indicates the current event phase:<OL>
* <LI> capture phase: starting from the top parent to the target</LI>
* <LI> at target phase: currently being dispatched from the target</LI>
* <LI> bubbling phase: from the target to the top parent</LI>
* </OL>
* @property eventPhase
* @type Number
* @default 0
* @readonly
*/
p.eventPhase = 0;
/**
* Indicates whether the event will bubble through the display list.
* @property bubbles
* @type Boolean
* @default false
* @readonly
*/
p.bubbles = false;
/**
* Indicates whether the default behaviour of this event can be cancelled via
* {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor.
* @property cancelable
* @type Boolean
* @default false
* @readonly
*/
p.cancelable = false;
/**
* The epoch time at which this event was created.
* @property timeStamp
* @type Number
* @default 0
* @readonly
*/
p.timeStamp = 0;
/**
* Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
* on this event.
* @property defaultPrevented
* @type Boolean
* @default false
* @readonly
*/
p.defaultPrevented = false;
/**
* Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or
* {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event.
* @property propagationStopped
* @type Boolean
* @default false
* @readonly
*/
p.propagationStopped = false;
/**
* Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
* on this event.
* @property immediatePropagationStopped
* @type Boolean
* @default false
* @readonly
*/
p.immediatePropagationStopped = false;
/**
* Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
* @property removed
* @type Boolean
* @default false
* @readonly
*/
p.removed = false;
// constructor:
/**
* Initialization method.
* @method initialize
* @param {String} type The event type.
* @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
* @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
* @protected
**/
p.initialize = function(type, bubbles, cancelable) {
this.type = type;
this.bubbles = bubbles;
this.cancelable = cancelable;
this.timeStamp = (new Date()).getTime();
};
// public methods:
/**
* Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true.
* Mirrors the DOM event standard.
* @method preventDefault
**/
p.preventDefault = function() {
this.defaultPrevented = true;
};
/**
* Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true.
* Mirrors the DOM event standard.
* @method stopPropagation
**/
p.stopPropagation = function() {
this.propagationStopped = true;
};
/**
* Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and
* {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true.
* Mirrors the DOM event standard.
* @method stopImmediatePropagation
**/
p.stopImmediatePropagation = function() {
this.immediatePropagationStopped = this.propagationStopped = true;
};
/**
* Causes the active listener to be removed via removeEventListener();
*
* myBtn.addEventListener("click", function(evt) {
* // do stuff...
* evt.remove(); // removes this listener.
* });
*
* @method remove
**/
p.remove = function() {
this.removed = true;
};
/**
* Returns a clone of the Event instance.
* @method clone
* @return {Event} a clone of the Event instance.
**/
p.clone = function() {
return new Event(this.type, this.bubbles, this.cancelable);
};
/**
* Returns a string representation of this object.
* @method toString
* @return {String} a string representation of the instance.
**/
p.toString = function() {
return "[Event (type="+this.type+")]";
};
createjs.Event = Event;
}());
/*
* EventDispatcher
* 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.
*/
/**
* @module CreateJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* EventDispatcher provides methods for managing queues of event listeners and dispatching events.
*
* You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the
* EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method.
*
* Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the
* DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports
* bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent.
*
* EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier
* to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The
* {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to
* {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}.
*
* Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}}
* method, which can be used to listeners for all events, or listeners for a specific event. The Event object also
* includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener.
*
* <h4>Example</h4>
* Add EventDispatcher capabilities to the "MyClass" class.
*
* EventDispatcher.initialize(MyClass.prototype);
*
* Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}).
*
* instance.addEventListener("eventName", handlerMethod);
* function handlerMethod(event) {
* console.log(event.target + " Was Clicked");
* }
*
* <b>Maintaining proper scope</b><br />
* Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}}
* method to subscribe to events simplifies this.
*
* instance.addEventListener("click", function(event) {
* console.log(instance == this); // false, scope is ambiguous.
* });
*
* instance.on("click", function(event) {
* console.log(instance == this); // true, "on" uses dispatcher scope by default.
* });
*
* If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope.
*
*
* @class EventDispatcher
* @constructor
**/
var EventDispatcher = function() {
/* this.initialize(); */ // not needed.
};
var p = EventDispatcher.prototype;
/**
* Static initializer to mix EventDispatcher methods into a target object or prototype.
*
* EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class
* EventDispatcher.initialize(myObject); // add to a specific instance
*
* @method initialize
* @static
* @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a
* prototype.
**/
EventDispatcher.initialize = function(target) {
target.addEventListener = p.addEventListener;
target.on = p.on;
target.removeEventListener = target.off = p.removeEventListener;
target.removeAllEventListeners = p.removeAllEventListeners;
target.hasEventListener = p.hasEventListener;
target.dispatchEvent = p.dispatchEvent;
target._dispatchEvent = p._dispatchEvent;
target.willTrigger = p.willTrigger;
};
// constructor:
// private properties:
/**
* @protected
* @property _listeners
* @type Object
**/
p._listeners = null;
/**
* @protected
* @property _captureListeners
* @type Object
**/
p._captureListeners = null;
// constructor:
/**
* Initialization method.
* @method initialize
* @protected
**/
p.initialize = function() {};
// public methods:
/**
* Adds the specified event listener. Note that adding multiple listeners to the same function will result in
* multiple callbacks getting fired.
*
* <h4>Example</h4>
*
* displayObject.addEventListener("click", handleClick);
* function handleClick(event) {
* // Click happened.
* }
*
* @method addEventListener
* @param {String} type The string type of the event.
* @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
* the event is dispatched.
* @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
* @return {Function | Object} Returns the listener for chaining or assignment.
**/
p.addEventListener = function(type, listener, useCapture) {
var listeners;
if (useCapture) {
listeners = this._captureListeners = this._captureListeners||{};
} else {
listeners = this._listeners = this._listeners||{};
}
var arr = listeners[type];
if (arr) { this.removeEventListener(type, listener, useCapture); }
arr = listeners[type]; // remove may have deleted the array
if (!arr) { listeners[type] = [listener]; }
else { arr.push(listener); }
return listener;
};
/**
* A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener
* only run once, associate arbitrary data with the listener, and remove the listener.
*
* This method works by creating an anonymous wrapper function and subscribing it with addEventListener.
* The created anonymous function is returned for use with .removeEventListener (or .off).
*
* <h4>Example</h4>
*
* var listener = myBtn.on("click", handleClick, null, false, {count:3});
* function handleClick(evt, data) {
* data.count -= 1;
* console.log(this == myBtn); // true - scope defaults to the dispatcher
* if (data.count == 0) {
* alert("clicked 3 times!");
* myBtn.off("click", listener);
* // alternately: evt.remove();
* }
* }
*
* @method on
* @param {String} type The string type of the event.
* @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
* the event is dispatched.
* @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent).
* @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered.
* @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called.
* @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
* @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener.
**/
p.on = function(type, listener, scope, once, data, useCapture) {
if (listener.handleEvent) {
scope = scope||listener;
listener = listener.handleEvent;
}
scope = scope||this;
return this.addEventListener(type, function(evt) {
listener.call(scope, evt, data);
once&&evt.remove();
}, useCapture);
};
/**
* Removes the specified event listener.
*
* <b>Important Note:</b> that you must pass the exact function reference used when the event was added. If a proxy
* function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or
* closure will not work.
*
* <h4>Example</h4>
*
* displayObject.removeEventListener("click", handleClick);
*
* @method removeEventListener
* @param {String} type The string type of the event.
* @param {Function | Object} listener The listener function or object.
* @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
**/
p.removeEventListener = function(type, listener, useCapture) {
var listeners = useCapture ? this._captureListeners : this._listeners;
if (!listeners) { return; }
var arr = listeners[type];
if (!arr) { return; }
for (var i=0,l=arr.length; i<l; i++) {
if (arr[i] == listener) {
if (l==1) { delete(listeners[type]); } // allows for faster checks.
else { arr.splice(i,1); }
break;
}
}
};
/**
* A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the
* .on method.
*
* @method off
* @param {String} type The string type of the event.
* @param {Function | Object} listener The listener function or object.
* @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
**/
p.off = p.removeEventListener;
/**
* Removes all listeners for the specified type, or all listeners of all types.
*
* <h4>Example</h4>
*
* // Remove all listeners
* displayObject.removeAllEventListeners();
*
* // Remove all click listeners
* displayObject.removeAllEventListeners("click");
*
* @method removeAllEventListeners
* @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed.
**/
p.removeAllEventListeners = function(type) {
if (!type) { this._listeners = this._captureListeners = null; }
else {
if (this._listeners) { delete(this._listeners[type]); }
if (this._captureListeners) { delete(this._captureListeners[type]); }
}
};
/**
* Dispatches the specified event to all listeners.
*
* <h4>Example</h4>
*
* // Use a string event
* this.dispatchEvent("complete");
*
* // Use an Event instance
* var event = new createjs.Event("progress");
* this.dispatchEvent(event);
*
* @method dispatchEvent
* @param {Object | String | Event} eventObj An object with a "type" property, or a string type.
* While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used,
* dispatchEvent will construct an Event instance with the specified type.
* @param {Object} [target] The object to use as the target property of the event object. This will default to the
* dispatching object. <b>This parameter is deprecated and will be removed.</b>
* @return {Boolean} Returns the value of eventObj.defaultPrevented.
**/
p.dispatchEvent = function(eventObj, target) {
if (typeof eventObj == "string") {
// won't bubble, so skip everything if there's no listeners:
var listeners = this._listeners;
if (!listeners || !listeners[eventObj]) { return false; }
eventObj = new createjs.Event(eventObj);
}
// TODO: deprecated. Target param is deprecated, only use case is MouseEvent/mousemove, remove.
eventObj.target = target||this;
if (!eventObj.bubbles || !this.parent) {
this._dispatchEvent(eventObj, 2);
} else {
var top=this, list=[top];
while (top.parent) { list.push(top = top.parent); }
var i, l=list.length;
// capture & atTarget
for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) {
list[i]._dispatchEvent(eventObj, 1+(i==0));
}
// bubbling
for (i=1; i<l && !eventObj.propagationStopped; i++) {
list[i]._dispatchEvent(eventObj, 3);
}
}
return eventObj.defaultPrevented;
};
/**
* Indicates whether there is at least one listener for the specified event type.
* @method hasEventListener
* @param {String} type The string type of the event.
* @return {Boolean} Returns true if there is at least one listener for the specified event.
**/
p.hasEventListener = function(type) {
var listeners = this._listeners, captureListeners = this._captureListeners;
return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type]));
};
/**
* Indicates whether there is at least one listener for the specified event type on this object or any of its
* ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the
* specified type is dispatched from this object, it will trigger at least one listener.
*
* This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire
* event flow for a listener, not just this object.
* @method willTrigger
* @param {String} type The string type of the event.
* @return {Boolean} Returns `true` if there is at least one listener for the specified event.
**/
p.willTrigger = function(type) {
var o = this;
while (o) {
if (o.hasEventListener(type)) { return true; }
o = o.parent;
}
return false;
};
/**
* @method toString
* @return {String} a string representation of the instance.
**/
p.toString = function() {
return "[EventDispatcher]";
};
// private methods:
/**
* @method _dispatchEvent
* @param {Object | String | Event} eventObj
* @param {Object} eventPhase
* @protected
**/
p._dispatchEvent = function(eventObj, eventPhase) {
var l, listeners = (eventPhase==1) ? this._captureListeners : this._listeners;
if (eventObj && listeners) {
var arr = listeners[eventObj.type];
if (!arr||!(l=arr.length)) { return; }
eventObj.currentTarget = this;
eventObj.eventPhase = eventPhase;
eventObj.removed = false;
arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch
for (var i=0; i<l && !eventObj.immediatePropagationStopped; i++) {
var o = arr[i];
if (o.handleEvent) { o.handleEvent(eventObj); }
else { o(eventObj); }
if (eventObj.removed) {
this.off(eventObj.type, o, eventPhase==1);
eventObj.removed = false;
}
}
}
};
createjs.EventDispatcher = EventDispatcher;
}());
/*
* 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 1s then call the <code>handleComplete</code> function.
*
* target.alpha = 0;
* 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.
*
* 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;
* Tween.get(target).wait(500).to({alpha:0, visible:false}, 1000).call(handleComplete);
* function handleComplete() {
* //Tween complete
* }
*
* <h4>Required Support<h4>
* Tweenjs requires a ticker function, which is included in <a href="http://www.easeljs.com">EaselJS</a>.
* If you are not using EaselJS, you must build your own ticker function that calls {{#crossLink "Tween/tick"}}{{/crossLink}}
* on the tweens.
*
* <h4>Browser Support</h4>
* TweenJS will work in all browsers.
*
* @module TweenJS
* @main TweenJS
*/
// TODO: possibly add a END actionsMode (only runs actions that == position)?
// TODO: evaluate a way to decouple paused from tick registration.
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* A Tween instance tweens properties for a single target. Instance methods can be chained for easy construction and sequencing:
*
* <h4>Example</h4>
*
* target.alpha = 1;
* Tween.get(target)
* .wait(500)
* .to({alpha:0, visible:false}, 1000)
* .call(handleComplete);
* function handleComplete() {
* //Tween complete
* }
*
* Multiple tweens can point to the same instance, 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 <code>override:true</code>
* in the props argument.
*
* Tween.get(target, {override:true}).to({x:100});
*
* Subscribe to the "change" event to get notified when a property of the target is changed.
*
* Tween.get(target, {override:true}).to({x:100}).addEventListener("change", handleChange);
* function handleChange(event) {
* // The tween changed.
* }
*
* See the Tween {{#crossLink "Tween/get"}}{{/crossLink}} method for additional param documentation.
* @class Tween
* @param {Object} target The target object that will have its properties tweened.
* @param {Object} [props] The configuration properties to apply to this tween instance (ex. `{loop:true, paused:true}`.
* All properties default to false. Supported props are:<UL>
* <LI> loop: sets the loop property on this tween.</LI>
* <LI> useTicks: uses ticks for all durations instead of milliseconds.</LI>
* <LI> ignoreGlobalPause: sets the ignoreGlobalPause property on this tween.</LI>
* <LI> override: if true, `Tween.removeTweens(target)` will be called to remove any other tweens with the same target.
* <LI> paused: indicates whether to start the tween paused.</LI>
* <LI> position: indicates the initial position for this tween.</LI>
* <LI> onChange: specifies a listener for the "change" event.</LI>
* </UL>
* @param {Object} [pluginData] An object containing data for use by installed plugins. See individual
* plugins' documentation for details.
* @extends EventDispatcher
* @constructor
*/
var Tween = function(target, props, pluginData) {
this.initialize(target, props, pluginData);
};
var p = Tween.prototype = new createjs.EventDispatcher();
// static interface:
/**
* Constant defining the none actionsMode for use with setPosition.
* @property NONE
* @type Number
* @default 0
* @static
*/
Tween.NONE = 0;
/**
* Constant defining the loop actionsMode for use with setPosition.
* @property LOOP
* @type Number
* @default 1
* @static
*/
Tween.LOOP = 1;
/**
* Constant defining the reverse actionsMode for use with setPosition.
* @property REVERSE
* @type Number
* @default 2
* @static
*/
Tween.REVERSE = 2;
/**
* 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 = {};
/**
* Returns a new tween instance. This is functionally identical to using "new Tween(...)", but looks cleaner
* with the chained syntax of TweenJS.
* @example
* var tween = createjs.Tween.get(target);
* @method get
* @param {Object} target The target object that will have its properties tweened.
* @param {Object} [props] The configuration properties to apply to this tween instance (ex. <code>{loop:true, paused:true}</code>).
* All properties default to false. Supported props are:<UL>
* <LI> loop: sets the loop property on this tween.</LI>
* <LI> useTicks: uses ticks for all durations instead of milliseconds.</LI>
* <LI> ignoreGlobalPause: sets the ignoreGlobalPause property on this tween.</LI>
* <LI> override: if true, Tween.removeTweens(target) will be called to remove any other tweens with the same target.
* <LI> paused: indicates whether to start the tween paused.</LI>
* <LI> position: indicates the initial position for this tween.</LI>
* <LI> onChange: specifies a listener for the "change" event.</LI>
* </UL>
* @param {Object} [pluginData] An object containing data for use by installed plugins. See individual
* plugins' documentation for details.
* @param {Boolean} [override=false] If true, any previous tweens on the same target will be removed. This is the same as
* calling <code>Tween.removeTweens(target)</code>.
* @return {Tween} A reference to the created tween. Additional chained tweens, method calls, or callbacks can be
* applied to the returned tween instance.
* @static
*/
Tween.get = function(target, props, pluginData, override) {
if (override) { Tween.removeTweens(target); }
return new Tween(target, props, pluginData);
};
/**
* Advances all tweens. This typically uses the Ticker class (available in the EaselJS library), but you can call it
* manually if you prefer to use your own "heartbeat" implementation.
*
* Note: Currently, EaselJS must be included <em>before</em> TweenJS to ensure Ticker exists during initialization.
* @method tick
* @param {Number} delta The change in time in milliseconds since the last tick. Required unless all tweens have
* <code>useTicks</code> set to true.
* @param {Boolean} paused Indicates whether a global pause is in effect. Tweens with <code>ignoreGlobalPause</code>
* will ignore this, but all others will pause if this is true.
* @static
*/
Tween.tick = function(delta, paused) {
var tweens = Tween._tweens.slice(); // to avoid race conditions.
for (var i=tweens.length-1; i>=0; i--) {
var tween = tweens[i];
if ((paused && !tween.ignoreGlobalPause) || tween._paused) { continue; }
tween.tick(tween._useTicks?1:delta);
}
};
/**
* Handle events that result from Tween being used as an event handler. This is included to allow Tween to handle
* tick events from <code>createjs.Ticker</code>. No other events are handled in Tween.
* @method handleEvent
* @param {Object} event An event object passed in by the EventDispatcher. 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 <code>override</code>
* property is <code>true</code>.
* @method removeTweens
* @param {Object} target The target object to remove existing tweens from.
* @static
*/
Tween.removeTweens = function(target) {
if (!target.tweenjs_count) { return; }
var tweens = Tween._tweens;
for (var i=tweens.length-1; i>=0; i--) {
if (tweens[i]._target == target) {
tweens[i]._paused = true;
tweens.splice(i,1);
}
}
target.tweenjs_count = 0;
};
/**
* Stop and remove all existing tweens.
* @method removeAllTweens
* @static
* @since 0.4.1
*/
Tween.removeAllTweens = function() {
var tweens = Tween._tweens;
for (var i= 0, l=tweens.length; i<l; i++) {
var tween = tweens[i];
tween.paused = true;
tween.target.tweenjs_count = 0;
}
tweens.length = 0;
};
/**
* Indicates whether there are any active tweens (and how many) 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} If there are active tweens.
* @static
*/
Tween.hasActiveTweens = function(target) {
if (target) { return target.tweenjs_count; }
return Tween._tweens && !!Tween._tweens.length;
};
/**
* Installs a plugin, which can modify how certain properties are handled when tweened. See the CSSPlugin for an
* example of how to write TweenJS plugins.
* @method installPlugin
* @static
* @param {Object} plugin The plugin class to install
* @param {Array} properties An array of properties that the plugin will handle.
*/
Tween.installPlugin = function(plugin, properties) {
var priority = plugin.priority;
if (priority == null) { plugin.priority = priority = 0; }
for (var i=0,l=properties.length,p=Tween._plugins;i<l;i++) {
var n = properties[i];
if (!p[n]) { p[n] = [plugin]; }
else {
var arr = p[n];
for (var j=0,jl=arr.length;j<jl;j++) {
if (priority < arr[j].priority) { break; }
}
p[n].splice(j,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} value If true, the tween is registered. If false the tween is unregistered.
* @static
* @protected
*/
Tween._register = function(tween, value) {
var target = tween._target;
var tweens = Tween._tweens;
if (value) {
// TODO: this approach might fail if a dev is using sealed objects in ES5
if (target) { target.tweenjs_count = target.tweenjs_count ? target.tweenjs_count+1 : 1; }
tweens.push(tween);
if (!Tween._inited && createjs.Ticker) { createjs.Ticker.addEventListener("tick", Tween); Tween._inited = true; }
} else {
if (target) { target.tweenjs_count--; }
var i = tweens.length;
while (i--) {
if (tweens[i] == tween) {
tweens.splice(i, 1);
return;
}
}
}
};
// public properties:
/**
* Causes this tween to continue playing when a global pause is active. For example, if TweenJS is using Ticker,
* then setting this to true (the default) will cause this tween to be paused when <code>Ticker.setPaused(true)</code> is called.
* See Tween.tick() for more info. Can be set via the props param.
* @property ignoreGlobalPause
* @type Boolean
* @default false
*/
p.ignoreGlobalPause = false;
/**
* If true, the tween will loop when it reaches the end. Can be set via the props param.
* @property loop
* @type {Boolean}
* @default false
*/
p.loop = false;
/**
* Read-only. Specifies the total duration of this tween in milliseconds (or ticks if useTicks is true).
* This value is automatically updated as you modify the tween. Changing it directly could result in unexpected
* behaviour.
* @property duration
* @type {Number}
* @default 0
*/
p.duration = 0;
/**
* Allows you to specify data that will be used by installed plugins. Each plugin uses this differently, but in general
* you specify data by setting it to a property of pluginData with the same name as the plugin class.
* @example
* myTween.pluginData.PluginClassName = data;
* <br/>
* Also, most plugins support a property to enable or disable them. This is typically the plugin class name followed by "_enabled".<br/>
* @example
* myTween.pluginData.PluginClassName_enabled = false;<br/>
* <br/>
* Some plugins also store instance data in this object, usually in a property named _PluginClassName.
* See the documentation for individual plugins for more details.
* @property pluginData
* @type {Object}
*/
p.pluginData = null;
// TODO: deprecated.
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "Tween/change:event"}}{{/crossLink}}
* event.
* @property onChange
* @type {Function}
* @deprecated Use addEventListener and the "change" event.
*/
/**
* Read-only. The target of this tween. This is the object on which the tweened properties will be changed. Changing
* this property after the tween is created will not have any effect.
* @property target
* @type {Object}
*/
p.target = null;
/**
* Read-only. The current normalized position of the tween. This will always be a value between 0 and duration.
* Changing this property directly will have no effect.
* @property position
* @type {Object}
*/
p.position = null;
/**
* Read-only. Indicates the tween's current position is within a passive wait.
* @property passive
* @type {Boolean}
**/
p.passive = false;
// events:
/**
* Called whenever the tween's position changes.
* @event change
* @since 0.4.0
**/
// private properties:
/**
* @property _paused
* @type {Boolean}
* @default false
* @protected
*/
p._paused = false;
/**
* @property _curQueueProps
* @type {Object}
* @protected
*/
p._curQueueProps = null;
/**
* @property _initQueueProps
* @type {Object}
* @protected
*/
p._initQueueProps = null;
/**
* @property _steps
* @type {Array}
* @protected
*/
p._steps = null;
/**
* @property _actions
* @type {Array}
* @protected
*/
p._actions = null;
/**
* Raw position.
* @property _prevPosition
* @type {Number}
* @default 0
* @protected
*/
p._prevPosition = 0;
/**
* The position within the current step.
* @property _stepPosition
* @type {Number}
* @default 0
* @protected
*/
p._stepPosition = 0; // this is needed by MovieClip.
/**
* Normalized position.
* @property _prevPos
* @type {Number}
* @default -1
* @protected
*/
p._prevPos = -1;
/**
* @property _target
* @type {Object}
* @protected
*/
p._target = null;
/**
* @property _useTicks
* @type {Boolean}
* @default false
* @protected
*/
p._useTicks = false;
/**
* @property _inited
* @type {boolean}
* @default false
* @protected
*/
p._inited = false;
// constructor:
/**
* @method initialize
* @param {Object} target
* @param {Object} props
* @param {Object} pluginData
* @protected
*/
p.initialize = function(target, props, pluginData) {
this.target = this._target = target;
if (props) {
this._useTicks = props.useTicks;
this.ignoreGlobalPause = props.ignoreGlobalPause;
this.loop = props.loop;
props.onChange&&this.addEventListener("change", props.onChange);
if (props.override) { Tween.removeTweens(target); }
}
this.pluginData = pluginData || {};
this._curQueueProps = {};
this._initQueueProps = {};
this._steps = [];
this._actions = [];
if (props&&props.paused) { this._paused=true; }
else { Tween._register(this,true); }
if (props&&props.position!=null) { this.setPosition(props.position, Tween.NONE); }
};
// public methods:
/**
* Queues a wait (essentially an empty tween).
* @example
* //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 <code>useTicks</code> is true).
* @param {Boolean} passive Tween properties will not be updated during a passive wait. This
* is mostly useful for use with Timeline's that contain multiple tweens affecting the same target
* at different times.
* @return {Tween} This tween instance (for chaining calls).
**/
p.wait = function(duration, passive) {
if (duration == null || duration <= 0) { return this; }
var o = this._cloneProps(this._curQueueProps);
return this._addStep({d:duration, p0:o, e:this._linearEase, p1:o, v:passive});
};
/**
* Queues a tween from the current values to the target 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.
* @example
* createjs.Tween.get(target).to({alpha:0}, 1000);
* @method to
* @param {Object} props An object specifying property target values for this tween (Ex. <code>{x:300}</code> would tween the x
* property of the target to 300).
* @param {Number} duration Optional. The duration of the wait in milliseconds (or in ticks if <code>useTicks</code> is true).
* Defaults to 0.
* @param {Function} ease Optional. The easing function to use for this tween. Defaults to a linear ease.
* @return {Tween} This tween instance (for chaining calls).
*/
p.to = function(props, duration, ease) {
if (isNaN(duration) || duration < 0) { duration = 0; }
return this._addStep({d:duration||0, p0:this._cloneProps(this._curQueueProps), e:ease, p1:this._cloneProps(this._appendQueueProps(props))});
};
/**
* Queues an action to call the specified function.
* @example
* //would call myFunction() after 1s.
* myTween.wait(1000).call(myFunction);
* @method call
* @param {Function} callback The function to call.
* @param {Array} params Optional. 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 Optional. 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).
*/
p.call = function(callback, params, scope) {
return this._addAction({f:callback, p:params ? params : [this], o:scope ? scope : this._target});
};
// TODO: add clarification between this and a 0 duration .to:
/**
* Queues an action to set the specified props on the specified target. If target is null, it will use this tween's
* target.
* @example
* myTween.wait(1000).set({visible:false},foo);
* @method set
* @param {Object} props The properties to set (ex. <code>{visible:false}</code>).
* @param {Object} target Optional. 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).
*/
p.set = function(props, target) {
return this._addAction({f:this._set, o:this, p:[props, target ? target : this._target]});
};
/**
* Queues an action to to play (unpause) the specified tween. This enables you to sequence multiple tweens.
* @example
* myTween.to({x:100},500).play(otherTween);
* @method play
* @param {Tween} tween The tween to play.
* @return {Tween} This tween instance (for chaining calls).
*/
p.play = function(tween) {
if (!tween) { tween = this; }
return this.call(tween.setPaused, [false], tween);
};
/**
* Queues an action to to pause the specified tween.
* @method pause
* @param {Tween} tween The tween to play. If null, it pauses this tween.
* @return {Tween} This tween instance (for chaining calls)
*/
p.pause = function(tween) {
if (!tween) { tween = this; }
return this.call(tween.setPaused, [true], tween);
};
/**
* Advances the tween to a specified position.
* @method setPosition
* @param {Number} value The position to seek to in milliseconds (or ticks if useTicks is true).
* @param {Number} actionsMode Optional parameter specifying how actions are handled (ie. call, set, play, pause):
* <code>Tween.NONE</code> (0) - run no actions. <code>Tween.LOOP</code> (1) - if new position is less than old, then run all actions
* between old and duration, then all actions between 0 and new. Defaults to <code>LOOP</code>. <code>Tween.REVERSE</code> (2) - if new
* position is less than old, run all actions between them in reverse.
* @return {Boolean} Returns true if the tween is complete (ie. the full tween has run & loop is false).
*/
p.setPosition = function(value, actionsMode) {
if (value < 0) { value = 0; }
if (actionsMode == null) { actionsMode = 1; }
// normalize position:
var t = value;
var end = false;
if (t >= this.duration) {
if (this.loop) { t = t%this.duration; }
else {
t = this.duration;
end = true;
}
}
if (t == this._prevPos) { return end; }
var prevPos = this._prevPos;
this.position = this._prevPos = t; // set this in advance in case an action modifies position.
this._prevPosition = value;
// handle tweens:
if (this._target) {
if (end) {
// addresses problems with an ending zero length step.
this._updateTargetProps(null,1);
} else if (this._steps.length > 0) {
// find our new tween index:
for (var i=0, l=this._steps.length; i<l; i++) {
if (this._steps[i].t > t) { break; }
}
var step = this._steps[i-1];
this._updateTargetProps(step,(this._stepPosition = t-step.t)/step.d);
}
}
// run actions:
if (actionsMode != 0 && this._actions.length > 0) {
if (this._useTicks) {
// only run the actions we landed on.
this._runActions(t,t);
} else if (actionsMode == 1 && t<prevPos) {
if (prevPos != this.duration) { this._runActions(prevPos, this.duration); }
this._runActions(0, t, true);
} else {
this._runActions(prevPos, t);
}
}
if (end) { this.setPaused(true); }
this.dispatchEvent("change");
return end;
};
/**
* Advances this tween by the specified amount of time in milliseconds (or ticks if <code>useTicks</code> is true).
* This is normally called automatically by the Tween engine (via <code>Tween.tick</code>), but is exposed for advanced uses.
* @method tick
* @param {Number} delta The time to advance in milliseconds (or ticks if <code>useTicks</code> is true).
*/
p.tick = function(delta) {
if (this._paused) { return; }
this.setPosition(this._prevPosition+delta);
};
/**
* Pauses or plays this tween.
* @method setPaused
* @param {Boolean} value Indicates whether the tween should be paused (true) or played (false).
* @return {Tween} This tween instance (for chaining calls)
*/
p.setPaused = function(value) {
this._paused = !!value;
Tween._register(this, !value);
return this;
};
// 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:
/**
* @method _updateTargetProps
* @param {Object} step
* @param {Number} ratio
* @protected
*/
p._updateTargetProps = function(step, ratio) {
var p0,p1,v,v0,v1,arr;
if (!step && ratio == 1) {
// GDS: when does this run? Just at the very end? Shouldn't.
this.passive = false;
p0 = p1 = this._curQueueProps;
} else {
this.passive = !!step.v;
if (this.passive) { return; } // don't update props.
// apply ease to ratio.
if (step.e) { ratio = step.e(ratio,0,1,1); }
p0 = step.p0;
p1 = step.p1;
}
for (var n in this._initQueueProps) {
if ((v0 = p0[n]) == null) { p0[n] = v0 = this._initQueueProps[n]; }
if ((v1 = p1[n]) == null) { p1[n] = v1 = v0; }
if (v0 == v1 || ratio == 0 || ratio == 1 || (typeof(v0) != "number")) {
// no interpolation - either at start, end, values don't change, or the value is non-numeric.
v = ratio == 1 ? v1 : v0;
} else {
v = v0+(v1-v0)*ratio;
}
var ignore = false;
if (arr = Tween._plugins[n]) {
for (var i=0,l=arr.length;i<l;i++) {
var v2 = arr[i].tween(this, n, v, p0, p1, ratio, !!step&&p0==p1, !step);
if (v2 == Tween.IGNORE) { ignore = true; }
else { v = v2; }
}
}
if (!ignore) { this._target[n] = v; }
}
};
/**
* @method _runActions
* @param {Number} startPos
* @param {Number} endPos
* @param {Boolean} includeStart
* @protected
*/
p._runActions = function(startPos, endPos, includeStart) {
var sPos = startPos;
var ePos = endPos;
var i = -1;
var j = this._actions.length;
var k = 1;
if (startPos > endPos) {
// running backwards, flip everything:
sPos = endPos;
ePos = startPos;
i = j;
j = k = -1;
}
while ((i+=k) != j) {
var action = this._actions[i];
var pos = action.t;
if (pos == ePos || (pos > sPos && pos < ePos) || (includeStart && pos == startPos) ) {
action.f.apply(action.o, action.p);
}
}
};
/**
* @method _appendQueueProps
* @param {Object} o
* @protected
*/
p._appendQueueProps = function(o) {
var arr,oldValue,i, l, injectProps;
for (var n in o) {
if (this._initQueueProps[n] === undefined) {
oldValue = this._target[n];
// init plugins:
if (arr = Tween._plugins[n]) {
for (i=0,l=arr.length;i<l;i++) {
oldValue = arr[i].init(this, n, oldValue);
}
}
this._initQueueProps[n] = this._curQueueProps[n] = (oldValue===undefined) ? null : oldValue;
} else {
oldValue = this._curQueueProps[n];
}
}
for (var n in o) {
oldValue = this._curQueueProps[n];
if (arr = Tween._plugins[n]) {
injectProps = injectProps||{};
for (i=0, l=arr.length;i<l;i++) {
// TODO: remove the check for .step in the next version. It's here for backwards compatibility.
if (arr[i].step) { arr[i].step(this, n, oldValue, o[n], injectProps); }
}
}
this._curQueueProps[n] = o[n];
}
if (injectProps) { this._appendQueueProps(injectProps); }
return this._curQueueProps;
};
/**
* @method _cloneProps
* @param {Object} props
* @protected
*/
p._cloneProps = function(props) {
var o = {};
for (var n in props) {
o[n] = props[n];
}
return o;
};
/**
* @method _addStep
* @param {Object} o
* @protected
*/
p._addStep = function(o) {
if (o.d > 0) {
this._steps.push(o);
o.t = this.duration;
this.duration += o.d;
}
return this;
};
/**
* @method _addAction
* @param {Object} o
* @protected
*/
p._addAction = function(o) {
o.t = this.duration;
this._actions.push(o);
return this;
};
/**
* @method _set
* @param {Object} props
* @param {Object} o
* @protected
*/
p._set = function(props, o) {
for (var n in props) {
o[n] = props[n];
}
};
createjs.Tween = Tween;
}());
/*
* Timeline
* 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.
*/
/**
* @module TweenJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* The Timeline class synchronizes multiple tweens and allows them to be controlled as a group. Please note that if a
* timeline is looping, the tweens on it may appear to loop even if the "loop" property of the tween is false.
* @class Timeline
* @param {Array} tweens An array of Tweens to add to this timeline. See addTween for more info.
* @param {Object} labels An object defining labels for using {{#crossLink "Timeline/gotoAndPlay"}}{{/crossLink}}/{{#crossLink "Timeline/gotoAndStop"}}{{/crossLink}}.
* See {{#crossLink "Timeline/setLabels"}}{{/crossLink}}
* for details.
* @param {Object} props The configuration properties to apply to this tween instance (ex. `{loop:true}`). All properties
* default to false. Supported props are:<UL>
* <LI> loop: sets the loop property on this tween.</LI>
* <LI> useTicks: uses ticks for all durations instead of milliseconds.</LI>
* <LI> ignoreGlobalPause: sets the ignoreGlobalPause property on this tween.</LI>
* <LI> paused: indicates whether to start the tween paused.</LI>
* <LI> position: indicates the initial position for this timeline.</LI>
* <LI> onChange: specifies a listener to add for the {{#crossLink "Timeline/change:event"}}{{/crossLink}} event.</LI>
* </UL>
* @extends EventDispatcher
* @constructor
**/
var Timeline = function(tweens, labels, props) {
this.initialize(tweens, labels, props);
};
var p = Timeline.prototype = new createjs.EventDispatcher();
// public properties:
/**
* Causes this timeline to continue playing when a global pause is active.
* @property ignoreGlobalPause
* @type Boolean
**/
p.ignoreGlobalPause = false;
/**
* Read-only property specifying the total duration of this timeline in milliseconds (or ticks if useTicks is true).
* This value is usually automatically updated as you modify the timeline. See updateDuration for more information.
* @property duration
* @type Number
**/
p.duration = 0;
/**
* If true, the timeline will loop when it reaches the end. Can be set via the props param.
* @property loop
* @type Boolean
**/
p.loop = false;
// TODO: deprecated.
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "Timeline/change:event"}}{{/crossLink}}
* event.
* @property onChange
* @type Function
* @deprecated Use addEventListener and the "change" event.
**/
/**
* Read-only. The current normalized position of the timeline. This will always be a value between 0 and duration.
* Changing this property directly will have no effect.
* @property position
* @type Object
**/
p.position = null;
// events:
/**
* Called whenever the timeline's position changes.
* @event change
* @since 0.5.0
**/
// private properties:
/**
* @property _paused
* @type Boolean
* @protected
**/
p._paused = false;
/**
* @property _tweens
* @type Array[Tween]
* @protected
**/
p._tweens = null;
/**
* @property _labels
* @type Object
* @protected
**/
p._labels = null;
/**
* @property _labelList
* @type Array[Object]
* @protected
**/
p._labelList = null;
/**
* @property _prevPosition
* @type Number
* @default 0
* @protected
**/
p._prevPosition = 0;
/**
* @property _prevPos
* @type Number
* @default -1
* @protected
**/
p._prevPos = -1;
/**
* @property _useTicks
* @type Boolean
* @default false
* @protected
**/
p._useTicks = false;
// constructor:
/**
* Initialization method.
* @method initialize
* @protected
**/
p.initialize = function(tweens, labels, props) {
this._tweens = [];
if (props) {
this._useTicks = props.useTicks;
this.loop = props.loop;
this.ignoreGlobalPause = props.ignoreGlobalPause;
props.onChange&&this.addEventListener("change", props.onChange);
}
if (tweens) { this.addTween.apply(this, tweens); }
this.setLabels(labels);
if (props&&props.paused) { this._paused=true; }
else { createjs.Tween._register(this,true); }
if (props&&props.position!=null) { this.setPosition(props.position, createjs.Tween.NONE); }
};
// public methods:
/**
* Adds one or more tweens (or timelines) to this timeline. The tweens will be paused (to remove them from the normal ticking system)
* and managed by this timeline. Adding a tween to multiple timelines will result in unexpected behaviour.
* @method addTween
* @param tween The tween(s) to add. Accepts multiple arguments.
* @return Tween The first tween that was passed in.
**/
p.addTween = function(tween) {
var l = arguments.length;
if (l > 1) {
for (var i=0; i<l; i++) { this.addTween(arguments[i]); }
return arguments[0];
} else if (l == 0) { return null; }
this.removeTween(tween);
this._tweens.push(tween);
tween.setPaused(true);
tween._paused = false;
tween._useTicks = this._useTicks;
if (tween.duration > this.duration) { this.duration = tween.duration; }
if (this._prevPos >= 0) { tween.setPosition(this._prevPos, createjs.Tween.NONE); }
return tween;
};
/**
* Removes one or more tweens from this timeline.
* @method removeTween
* @param tween The tween(s) to remove. Accepts multiple arguments.
* @return Boolean Returns true if all of the tweens were successfully removed.
**/
p.removeTween = function(tween) {
var l = arguments.length;
if (l > 1) {
var good = true;
for (var i=0; i<l; i++) { good = good && this.removeTween(arguments[i]); }
return good;
} else if (l == 0) { return false; }
var tweens = this._tweens;
var i = tweens.length;
while (i--) {
if (tweens[i] == tween) {
tweens.splice(i, 1);
if (tween.duration >= this.duration) { this.updateDuration(); }
return true;
}
}
return false;
};
/**
* Adds a label that can be used with {{#crossLink "Timeline/gotoAndPlay"}}{{/crossLink}}/{{#crossLink "Timeline/gotoAndStop"}}{{/crossLink}}.
* @method addLabel
* @param {String} label The label name.
* @param {Number} position The position this label represents.
**/
p.addLabel = function(label, position) {
this._labels[label] = position;
var list = this._labelList;
if (list) {
for (var i= 0,l=list.length; i<l; i++) { if (position < list[i].position) { break; } }
list.splice(i, 0, {label:label, position:position});
}
};
/**
* Defines labels for use with gotoAndPlay/Stop. Overwrites any previously set labels.
* @method setLabels
* @param {Object} o An object defining labels for using gotoAndPlay/Stop in the form `{labelName:time}` where time is in
* milliseconds (or ticks if `useTicks` is true).
**/
p.setLabels = function(o) {
this._labels = o ? o : {};
};
/**
* Returns a sorted list of the labels defined on this timeline.
* @method getLabels
* @return {Array[Object]} A sorted array of objects with label and position properties.
**/
p.getLabels = function() {
var list = this._labelList;
if (!list) {
list = this._labelList = [];
var labels = this._labels;
for (var n in labels) {
list.push({label:n, position:labels[n]});
}
list.sort(function (a,b) { return a.position- b.position; });
}
return list;
};
/**
* Returns the name of the label on or immediately before the current position. For example, given a timeline with
* two labels, "first" on frame index 4, and "second" on frame 8, getCurrentLabel would return:<UL>
* <LI>null if the current position is 2.</LI>
* <LI>"first" if the current position is 4.</LI>
* <LI>"first" if the current position is 7.</LI>
* <LI>"second" if the current position is 15.</LI></UL>
* @method getCurrentLabel
* @return {String} The name of the current label or null if there is no label
**/
p.getCurrentLabel = function() {
var labels = this.getLabels();
var pos = this.position;
var l = labels.length;
if (l) {
for (var i = 0; i<l; i++) { if (pos < labels[i].position) { break; } }
return (i==0) ? null : labels[i-1].label;
}
return null;
};
/**
* Unpauses this timeline and jumps to the specified position or label.
* @method gotoAndPlay
* @param {String|Number} positionOrLabel The position in milliseconds (or ticks if `useTicks` is true) or label to jump to.
**/
p.gotoAndPlay = function(positionOrLabel) {
this.setPaused(false);
this._goto(positionOrLabel);
};
/**
* Pauses this timeline and jumps to the specified position or label.
* @method gotoAndStop
* @param {String|Number} positionOrLabel The position in milliseconds (or ticks if `useTicks` is true) or label to jump to.
**/
p.gotoAndStop = function(positionOrLabel) {
this.setPaused(true);
this._goto(positionOrLabel);
};
/**
* Advances the timeline to the specified position.
* @method setPosition
* @param {Number} value The position to seek to in milliseconds (or ticks if `useTicks` is true).
* @param {Number} [actionsMode] parameter specifying how actions are handled. See the Tween {{#crossLink "Tween/setPosition"}}{{/crossLink}}
* method for more details.
* @return {Boolean} Returns true if the timeline is complete (ie. the full timeline has run & loop is false).
**/
p.setPosition = function(value, actionsMode) {
if (value < 0) { value = 0; }
var t = this.loop ? value%this.duration : value;
var end = !this.loop && value >= this.duration;
if (t == this._prevPos) { return end; }
this._prevPosition = value;
this.position = this._prevPos = t; // in case an action changes the current frame.
for (var i=0, l=this._tweens.length; i<l; i++) {
this._tweens[i].setPosition(t, actionsMode);
if (t != this._prevPos) { return false; } // an action changed this timeline's position.
}
if (end) { this.setPaused(true); }
this.dispatchEvent("change");
return end;
};
/**
* Pauses or plays this timeline.
* @method setPaused
* @param {Boolean} value Indicates whether the tween should be paused (true) or played (false).
**/
p.setPaused = function(value) {
this._paused = !!value;
createjs.Tween._register(this, !value);
};
/**
* Recalculates the duration of the timeline.
* The duration is automatically updated when tweens are added or removed, but this method is useful
* if you modify a tween after it was added to the timeline.
* @method updateDuration
**/
p.updateDuration = function() {
this.duration = 0;
for (var i=0,l=this._tweens.length; i<l; i++) {
var tween = this._tweens[i];
if (tween.duration > this.duration) { this.duration = tween.duration; }
}
};
/**
* Advances this timeline by the specified amount of time in milliseconds (or ticks if useTicks is true).
* This is normally called automatically by the Tween engine (via Tween.tick), but is exposed for advanced uses.
* @method tick
* @param {Number} delta The time to advance in milliseconds (or ticks if useTicks is true).
**/
p.tick = function(delta) {
this.setPosition(this._prevPosition+delta);
};
/**
* If a numeric position is passed, it is returned unchanged. If a string is passed, the position of the
* corresponding frame label will be returned, or null if a matching label is not defined.
* @method resolve
* @param {String|Number} positionOrLabel A numeric position value or label string.
**/
p.resolve = function(positionOrLabel) {
var pos = parseFloat(positionOrLabel);
if (isNaN(pos)) { pos = this._labels[positionOrLabel]; }
return pos;
};
/**
* Returns a string representation of this object.
* @method toString
* @return {String} a string representation of the instance.
**/
p.toString = function() {
return "[Timeline]";
};
/**
* @method clone
* @protected
**/
p.clone = function() {
throw("Timeline can not be cloned.")
};
// private methods:
/**
* @method _goto
* @protected
**/
p._goto = function(positionOrLabel) {
var pos = this.resolve(positionOrLabel);
if (pos != null) { this.setPosition(pos); }
};
createjs.Timeline = Timeline;
}());
/*
* Ease
* 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.
*/
/**
* @module TweenJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
// constructor:
/**
* The Ease class provides a collection of easing functions for use with TweenJS. It does not use the standard 4 param
* easing signature. Instead it uses a single param which indicates the current linear ratio (0 to 1) of the tween.
*
* Most methods on Ease can be passed directly as easing functions:
*
* Tween.get(target).to({x:100}, 500, Ease.linear);
*
* However, methods beginning with "get" will return an easing function based on parameter values:
*
* Tween.get(target).to({y:200}, 500, Ease.getPowIn(2.2));
*
* Please see the <a href="http://www.createjs.com/#!/TweenJS/demos/sparkTable">spark table demo</a> for an overview
* of the different ease types on <a href="http://tweenjs.com">TweenJS.com</a>.
*
* <i>Equations derived from work by Robert Penner.</i>
* @class Ease
* @static
**/
var Ease = function() {
throw "Ease cannot be instantiated.";
}
// public static methods:
/**
* @method linear
* @static
**/
Ease.linear = function(t) { return t; }
/**
* Identical to linear.
* @method none
* @static
**/
Ease.none = Ease.linear;
/**
* Mimics the simple -100 to 100 easing in Flash Pro.
* @method get
* @param amount A value from -1 (ease in) to 1 (ease out) indicating the strength and direction of the ease.
* @static
**/
Ease.get = function(amount) {
if (amount < -1) { amount = -1; }
if (amount > 1) { amount = 1; }
return function(t) {
if (amount==0) { return t; }
if (amount<0) { return t*(t*-amount+1+amount); }
return t*((2-t)*amount+(1-amount));
}
}
/**
* Configurable exponential ease.
* @method getPowIn
* @param pow The exponent to use (ex. 3 would return a cubic ease).
* @static
**/
Ease.getPowIn = function(pow) {
return function(t) {
return Math.pow(t,pow);
}
}
/**
* Configurable exponential ease.
* @method getPowOut
* @param pow The exponent to use (ex. 3 would return a cubic ease).
* @static
**/
Ease.getPowOut = function(pow) {
return function(t) {
return 1-Math.pow(1-t,pow);
}
}
/**
* Configurable exponential ease.
* @method getPowInOut
* @param pow The exponent to use (ex. 3 would return a cubic ease).
* @static
**/
Ease.getPowInOut = function(pow) {
return function(t) {
if ((t*=2)<1) return 0.5*Math.pow(t,pow);
return 1-0.5*Math.abs(Math.pow(2-t,pow));
}
}
/**
* @method quadIn
* @static
**/
Ease.quadIn = Ease.getPowIn(2);
/**
* @method quadOut
* @static
**/
Ease.quadOut = Ease.getPowOut(2);
/**
* @method quadInOut
* @static
**/
Ease.quadInOut = Ease.getPowInOut(2);
/**
* @method cubicIn
* @static
**/
Ease.cubicIn = Ease.getPowIn(3);
/**
* @method cubicOut
* @static
**/
Ease.cubicOut = Ease.getPowOut(3);
/**
* @method cubicInOut
* @static
**/
Ease.cubicInOut = Ease.getPowInOut(3);
/**
* @method quartIn
* @static
**/
Ease.quartIn = Ease.getPowIn(4);
/**
* @method quartOut
* @static
**/
Ease.quartOut = Ease.getPowOut(4);
/**
* @method quartInOut
* @static
**/
Ease.quartInOut = Ease.getPowInOut(4);
/**
* @method quintIn
* @static
**/
Ease.quintIn = Ease.getPowIn(5);
/**
* @method quintOut
* @static
**/
Ease.quintOut = Ease.getPowOut(5);
/**
* @method quintInOut
* @static
**/
Ease.quintInOut = Ease.getPowInOut(5);
/**
* @method sineIn
* @static
**/
Ease.sineIn = function(t) {
return 1-Math.cos(t*Math.PI/2);
}
/**
* @method sineOut
* @static
**/
Ease.sineOut = function(t) {
return Math.sin(t*Math.PI/2);
}
/**
* @method sineInOut
* @static
**/
Ease.sineInOut = function(t) {
return -0.5*(Math.cos(Math.PI*t) - 1)
}
/**
* Configurable "back in" ease.
* @method getBackIn
* @param amount The strength of the ease.
* @static
**/
Ease.getBackIn = function(amount) {
return function(t) {
return t*t*((amount+1)*t-amount);
}
}
/**
* @method backIn
* @static
**/
Ease.backIn = Ease.getBackIn(1.7);
/**
* Configurable "back out" ease.
* @method getBackOut
* @param amount The strength of the ease.
* @static
**/
Ease.getBackOut = function(amount) {
return function(t) {
return (--t*t*((amount+1)*t + amount) + 1);
}
}
/**
* @method backOut
* @static
**/
Ease.backOut = Ease.getBackOut(1.7);
/**
* Configurable "back in out" ease.
* @method getBackInOut
* @param amount The strength of the ease.
* @static
**/
Ease.getBackInOut = function(amount) {
amount*=1.525;
return function(t) {
if ((t*=2)<1) return 0.5*(t*t*((amount+1)*t-amount));
return 0.5*((t-=2)*t*((amount+1)*t+amount)+2);
}
}
/**
* @method backInOut
* @static
**/
Ease.backInOut = Ease.getBackInOut(1.7);
/**
* @method circIn
* @static
**/
Ease.circIn = function(t) {
return -(Math.sqrt(1-t*t)- 1);
}
/**
* @method circOut
* @static
**/
Ease.circOut = function(t) {
return Math.sqrt(1-(--t)*t);
}
/**
* @method circInOut
* @static
**/
Ease.circInOut = function(t) {
if ((t*=2) < 1) return -0.5*(Math.sqrt(1-t*t)-1);
return 0.5*(Math.sqrt(1-(t-=2)*t)+1);
}
/**
* @method bounceIn
* @static
**/
Ease.bounceIn = function(t) {
return 1-Ease.bounceOut(1-t);
}
/**
* @method bounceOut
* @static
**/
Ease.bounceOut = function(t) {
if (t < 1/2.75) {
return (7.5625*t*t);
} else if (t < 2/2.75) {
return (7.5625*(t-=1.5/2.75)*t+0.75);
} else if (t < 2.5/2.75) {
return (7.5625*(t-=2.25/2.75)*t+0.9375);
} else {
return (7.5625*(t-=2.625/2.75)*t +0.984375);
}
}
/**
* @method bounceInOut
* @static
**/
Ease.bounceInOut = function(t) {
if (t<0.5) return Ease.bounceIn (t*2) * .5;
return Ease.bounceOut(t*2-1)*0.5+0.5;
}
/**
* Configurable elastic ease.
* @method getElasticIn
* @param amplitude
* @param period
* @static
**/
Ease.getElasticIn = function(amplitude,period) {
var pi2 = Math.PI*2;
return function(t) {
if (t==0 || t==1) return t;
var s = period/pi2*Math.asin(1/amplitude);
return -(amplitude*Math.pow(2,10*(t-=1))*Math.sin((t-s)*pi2/period));
}
}
/**
* @method elasticIn
* @static
**/
Ease.elasticIn = Ease.getElasticIn(1,0.3);
/**
* Configurable elastic ease.
* @method getElasticOut
* @param amplitude
* @param period
* @static
**/
Ease.getElasticOut = function(amplitude,period) {
var pi2 = Math.PI*2;
return function(t) {
if (t==0 || t==1) return t;
var s = period/pi2 * Math.asin(1/amplitude);
return (amplitude*Math.pow(2,-10*t)*Math.sin((t-s)*pi2/period )+1);
}
}
/**
* @method elasticOut
* @static
**/
Ease.elasticOut = Ease.getElasticOut(1,0.3);
/**
* Configurable elastic ease.
* @method getElasticInOut
* @param amplitude
* @param period
* @static
**/
Ease.getElasticInOut = function(amplitude,period) {
var pi2 = Math.PI*2;
return function(t) {
var s = period/pi2 * Math.asin(1/amplitude);
if ((t*=2)<1) return -0.5*(amplitude*Math.pow(2,10*(t-=1))*Math.sin( (t-s)*pi2/period ));
return amplitude*Math.pow(2,-10*(t-=1))*Math.sin((t-s)*pi2/period)*0.5+1;
}
}
/**
* @method elasticInOut
* @static
**/
Ease.elasticInOut = Ease.getElasticInOut(1,0.3*1.5);
createjs.Ease = Ease;
}());
/*
* MotionGuidePlugin
* 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.
*/
/**
* @module TweenJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* A TweenJS plugin for working with motion guides.
*
* To use, install the plugin after TweenJS has loaded. Next tween the 'guide' property with an object as detailed below.
*
* createjs.MotionGuidePlugin.install();
*
* <h4>Example</h4>
*
* // Using a Motion Guide
* createjs.Tween.get(target).to({guide:{ path:[0,0, 0,200,200,200, 200,0,0,0] }},7000);
* // Visualizing the line
* graphics.moveTo(0,0).curveTo(0,200,200,200).curveTo(200,0,0,0);
*
* Each path needs pre-computation to ensure there's fast performance. Because of the pre-computation there's no
* built in support for path changes mid tween. These are the Guide Object's properties:<UL>
* <LI> path: Required, Array : The x/y points used to draw the path with a moveTo and 1 to n curveTo calls.</LI>
* <LI> start: Optional, 0-1 : Initial position, default 0 except for when continuing along the same path.</LI>
* <LI> end: Optional, 0-1 : Final position, default 1 if not specified.</LI>
* <LI> orient: Optional, string : "fixed"/"auto"/"cw"/"ccw"<UL>
* <LI>"fixed" forces the object to face down the path all movement (relative to start rotation),</LI>
* <LI>"auto" rotates the object along the path relative to the line.</LI>
* <LI>"cw"/"ccw" force clockwise or counter clockwise rotations including flash like behaviour</LI>
* </UL></LI>
* </UL>
* Guide objects should not be shared between tweens even if all properties are identical, the library stores
* information on these objects in the background and sharing them can cause unexpected behaviour. Values
* outside 0-1 range of tweens will be a "best guess" from the appropriate part of the defined curve.
*
* @class MotionGuidePlugin
* @constructor
**/
var MotionGuidePlugin = function() {
throw("MotionGuidePlugin cannot be instantiated.")
};
// static interface:
/**
* @property priority
* @protected
* @static
**/
MotionGuidePlugin.priority = 0; // high priority, should run sooner
/**
* @property temporary variable storage
* @private
* @static
*/
MotionGuidePlugin._rotOffS;
/**
* @property temporary variable storage
* @private
* @static
*/
MotionGuidePlugin._rotOffE;
/**
* @property temporary variable storage
* @private
* @static
*/
MotionGuidePlugin._rotNormS;
/**
* @property temporary variable storage
* @private
* @static
*/
MotionGuidePlugin._rotNormE;
/**
* Installs this plugin for use with TweenJS. Call this once after TweenJS is loaded to enable this plugin.
* @method install
* @static
**/
MotionGuidePlugin.install = function() {
createjs.Tween.installPlugin(MotionGuidePlugin, ["guide", "x", "y", "rotation"]);
return createjs.Tween.IGNORE;
};
/**
* @method init
* @protected
* @static
**/
MotionGuidePlugin.init = function(tween, prop, value) {
var target = tween.target;
if(!target.hasOwnProperty("x")){ target.x = 0; }
if(!target.hasOwnProperty("y")){ target.y = 0; }
if(!target.hasOwnProperty("rotation")){ target.rotation = 0; }
if(prop=="rotation"){ tween.__needsRot = true; }
return prop=="guide"?null:value;
};
/**
* @method step
* @protected
* @static
**/
MotionGuidePlugin.step = function(tween, prop, startValue, endValue, injectProps) {
// other props
if(prop == "rotation"){
tween.__rotGlobalS = startValue;
tween.__rotGlobalE = endValue;
MotionGuidePlugin.testRotData(tween, injectProps);
}
if(prop != "guide"){ return endValue; }
// guide only information - Start -
var temp, data = endValue;
if(!data.hasOwnProperty("path")){ data.path = []; }
var path = data.path;
if(!data.hasOwnProperty("end")){ data.end = 1; }
if(!data.hasOwnProperty("start")){
data.start = (startValue&&startValue.hasOwnProperty("end")&&startValue.path===path)?startValue.end:0;
}
// Figure out subline information
if(data.hasOwnProperty("_segments") && data._length){ return endValue; }
var l = path.length;
var accuracy = 10; // Adjust to improve line following precision but sacrifice performance (# of seg)
if(l >= 6 && (l-2) % 4 == 0){ // Enough points && contains correct number per entry ignoring start
data._segments = [];
data._length = 0;
for(var i=2; i<l; i+=4){
var sx = path[i-2], sy = path[i-1];
var cx = path[i+0], cy = path[i+1];
var ex = path[i+2], ey = path[i+3];
var oldX = sx, oldY = sy;
var tempX, tempY, total = 0;
var sublines = [];
for(var j=1; j<=accuracy; j++){
var t = j/accuracy;
var inv = 1 - t;
tempX = inv*inv * sx + 2 * inv * t * cx + t*t * ex;
tempY = inv*inv * sy + 2 * inv * t * cy + t*t * ey;
total += sublines[sublines.push(Math.sqrt((temp=tempX-oldX)*temp + (temp=tempY-oldY)*temp))-1];
oldX = tempX;
oldY = tempY;
}
data._segments.push(total);
data._segments.push(sublines);
data._length += total;
}
} else {
throw("invalid 'path' data, please see documentation for valid paths");
}
// Setup x/y tweens
temp = data.orient;
data.orient = true;
var o = {};
MotionGuidePlugin.calc(data, data.start, o);
tween.__rotPathS = Number(o.rotation.toFixed(5));
MotionGuidePlugin.calc(data, data.end, o);
tween.__rotPathE = Number(o.rotation.toFixed(5));
data.orient = false; //here and now we don't know if we need to
MotionGuidePlugin.calc(data, data.end, injectProps);
data.orient = temp;
// Setup rotation properties
if(!data.orient){ return endValue; }
tween.__guideData = data;
MotionGuidePlugin.testRotData(tween, injectProps);
return endValue;
};
/**
* @method testRotData
* @protected
* @static
**/
MotionGuidePlugin.testRotData = function(tween, injectProps){
// no rotation informat? if we need it come back, if we don't use 0 & ensure we have guide data
if(tween.__rotGlobalS === undefined || tween.__rotGlobalE === undefined){
if(tween.__needsRot){ return; }
if(tween._curQueueProps.rotation !== undefined){
tween.__rotGlobalS = tween.__rotGlobalE = tween._curQueueProps.rotation;
} else {
tween.__rotGlobalS = tween.__rotGlobalE = injectProps.rotation = tween.target.rotation || 0;
}
}
if(tween.__guideData === undefined){ return; }
// Process rotation properties
var data = tween.__guideData;
var rotGlobalD = tween.__rotGlobalE - tween.__rotGlobalS;
var rotPathD = tween.__rotPathE - tween.__rotPathS;
var rot = rotGlobalD - rotPathD;
if(data.orient == "auto"){
if(rot > 180){ rot -= 360; }
else if(rot < -180){ rot += 360; }
} else if(data.orient == "cw"){
while(rot < 0){ rot += 360; }
if(rot == 0 && rotGlobalD > 0 && rotGlobalD != 180){ rot += 360; }
} else if(data.orient == "ccw"){
rot = rotGlobalD - ((rotPathD > 180)?(360-rotPathD):(rotPathD)); // sign flipping on path
while(rot > 0){ rot -= 360; }
if(rot == 0 && rotGlobalD < 0 && rotGlobalD != -180){ rot -= 360; }
}
data.rotDelta = rot;
data.rotOffS = tween.__rotGlobalS - tween.__rotPathS;
// reset
tween.__rotGlobalS = tween.__rotGlobalE = tween.__guideData = tween.__needsRot = undefined;
};
/**
* @method tween
* @protected
* @static
**/
MotionGuidePlugin.tween = function(tween, prop, value, startValues, endValues, ratio, wait, end) {
var data = endValues.guide;
if(data == undefined || data === startValues.guide){ return value; }
if(data.lastRatio != ratio){
// first time through so calculate what I need to
var t = ((data.end-data.start)*(wait?data.end:ratio)+data.start);
MotionGuidePlugin.calc(data, t, tween.target);
switch(data.orient){
case "cw": // mix in the original rotation
case "ccw":
case "auto": tween.target.rotation += data.rotOffS + data.rotDelta*ratio; break;
case "fixed": // follow fixed behaviour to solve potential issues
default: tween.target.rotation += data.rotOffS; break;
}
data.lastRatio = ratio;
}
if(prop == "rotation" && ((!data.orient) || data.orient == "false")){ return value; }
return tween.target[prop];
};
/**
* Determine the appropriate x/y/rotation information about a path for a given ratio along the path.
* Assumes a path object with all optional parameters specified.
* @param data Data object you would pass to the "guide:" property in a Tween
* @param ratio 0-1 Distance along path, values outside 0-1 are "best guess"
* @param target Object to copy the results onto, will use a new object if not supplied.
* @return {Object} The target object or a new object w/ the tweened properties
* @static
*/
MotionGuidePlugin.calc = function(data, ratio, target) {
if(data._segments == undefined){ MotionGuidePlugin.validate(data); }
if(target == undefined){ target = {x:0, y:0, rotation:0}; }
var seg = data._segments;
var path = data.path;
// find segment
var pos = data._length * ratio;
var cap = seg.length - 2;
var n = 0;
while(pos > seg[n] && n < cap){
pos -= seg[n];
n+=2;
}
// find subline
var sublines = seg[n+1];
var i = 0;
cap = sublines.length-1;
while(pos > sublines[i] && i < cap){
pos -= sublines[i];
i++;
}
var t = (i/++cap)+(pos/(cap*sublines[i]));
// find x/y
n = (n*2)+2;
var inv = 1 - t;
target.x = inv*inv * path[n-2] + 2 * inv * t * path[n+0] + t*t * path[n+2];
target.y = inv*inv * path[n-1] + 2 * inv * t * path[n+1] + t*t * path[n+3];
// orientation
if(data.orient){
target.rotation = 57.2957795 * Math.atan2(
(path[n+1]-path[n-1])*inv + (path[n+3]-path[n+1])*t,
(path[n+0]-path[n-2])*inv + (path[n+2]-path[n+0])*t);
}
return target;
};
// public properties:
// private properties:
// constructor:
// public methods:
// private methods:
createjs.MotionGuidePlugin = MotionGuidePlugin;
}());
/**
* @module TweenJS
*/
this.createjs = this.createjs || {};
(function() {
"use strict";
/**
* Static class holding library specific information such as the version and buildDate of
* the library.
* @class TweenJS
**/
var s = createjs.TweenJS = createjs.TweenJS || {};
/**
* The version string for this release.
* @property version
* @type String
* @static
**/
s.version = /*version*/"NEXT"; // injected by build process
/**
* The build date for this release in UTC format.
* @property buildDate
* @type String
* @static
**/
s.buildDate = /*date*/"Thu, 12 Dec 2013 23:37:07 GMT"; // injected by build process
})();