/*
* DisplayObject
* 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 EaselJS Javascript library provides a retained graphics mode for canvas including a full hierarchical display
* list, a core interaction model, and helper classes to make working with 2D graphics in Canvas much easier.
* EaselJS provides straight forward solutions for working with rich graphics and interactivity with HTML5 Canvas...
*
* <h4>Getting Started</h4>
* To get started with Easel, create a {{#crossLink "Stage"}}{{/crossLink}} that wraps a CANVAS element, and add
* {{#crossLink "DisplayObject"}}{{/crossLink}} instances as children. EaselJS supports:
* <ul>
* <li>Images using {{#crossLink "Bitmap"}}{{/crossLink}}</li>
* <li>Vector graphics using {{#crossLink "Shape"}}{{/crossLink}} and {{#crossLink "Graphics"}}{{/crossLink}}</li>
* <li>Animated bitmaps using {{#crossLink "SpriteSheet"}}{{/crossLink}} and {{#crossLink "Sprite"}}{{/crossLink}}
* <li>Simple text instances using {{#crossLink "Text"}}{{/crossLink}}</li>
* <li>Containers that hold other DisplayObjects using {{#crossLink "Container"}}{{/crossLink}}</li>
* <li>Control HTML DOM elements using {{#crossLink "DOMElement"}}{{/crossLink}}</li>
* </ul>
*
* All display objects can be added to the stage as children, or drawn to a canvas directly.
*
* <b>User Interactions</b><br />
* All display objects on stage (except DOMElement) will dispatch events when interacted with using a mouse or
* touch. EaselJS supports hover, press, and release events, as well as an easy-to-use drag-and-drop model. Check out
* {{#crossLink "MouseEvent"}}{{/crossLink}} for more information.
*
* <h4>Simple Example</h4>
* This example illustrates how to create and position a {{#crossLink "Shape"}}{{/crossLink}} on the {{#crossLink "Stage"}}{{/crossLink}}
* using EaselJS' drawing API.
*
* //Create a stage by getting a reference to the canvas
* stage = new createjs.Stage("demoCanvas");
* //Create a Shape DisplayObject.
* circle = new createjs.Shape();
* circle.graphics.beginFill("red").drawCircle(0, 0, 40);
* //Set position of Shape instance.
* circle.x = circle.y = 50;
* //Add Shape instance to stage display list.
* stage.addChild(circle);
* //Update stage will render next frame
* stage.update();
*
* <b>Simple Interaction Example</b><br>
*
* displayObject.addEventListener("click", handleClick);
* function handleClick(event){
* // Click happenened
* }
*
* displayObject.addEventListener("mousedown", handlePress);
* function handlePress(event) {
* // A mouse press happened.
* // Listen for mouse move while the mouse is down:
* event.addEventListener("mousemove", handleMove);
* }
* function handleMove(event) {
* // Check out the DragAndDrop example in GitHub for more
* }
*
* <b>Simple Animation Example</b><br />
* This example moves the shape created in the previous demo across the screen.
*
* //Update stage will render next frame
* createjs.Ticker.addEventListener("tick", handleTick);
*
* function handleTick() {
* //Circle will move 10 units to the right.
* circle.x += 10;
* //Will cause the circle to wrap back
* if (circle.x > stage.canvas.width) { circle.x = 0; }
* stage.update();
* }
*
* <h4>Other Features</h4>
* EaselJS also has built in support for
* <ul><li>Canvas features such as {{#crossLink "Shadow"}}{{/crossLink}} and CompositeOperation</li>
* <li>{{#crossLink "Ticker"}}{{/crossLink}}, a global heartbeat that objects can subscribe to</li>
* <li>Filters, including a provided {{#crossLink "ColorMatrixFilter"}}{{/crossLink}}, {{#crossLink "AlphaMaskFilter"}}{{/crossLink}},
* {{#crossLink "AlphaMapFilter"}}{{/crossLink}}, and {{#crossLink "BlurFilter"}}{{/crossLink}}. See {{#crossLink "Filter"}}{{/crossLink}}
* for more information</li>
* <li>A {{#crossLink "ButtonHelper"}}{{/crossLink}} utility, to easily create interactive buttons</li>
* <li>{{#crossLink "SpriteSheetUtils"}}{{/crossLink}} and a {{#crossLink "SpriteSheetBuilder"}}{{/crossLink}} to
* help build and manage {{#crossLink "SpriteSheet"}}{{/crossLink}} functionality at run-time.</li>
* </ul>
*
* <h4>Browser Support</h4>
* All modern browsers that support Canvas will support EaselJS (<a href="http://caniuse.com/canvas">http://caniuse.com/canvas</a>).
* Browser performance may vary between platforms, for example, Android Canvas has poor hardware support, and is much
* slower on average than most other browsers.
*
* @module EaselJS
* @main EaselJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
// constructor:
/**
* DisplayObject is an abstract class that should not be constructed directly. Instead construct subclasses such as
* {{#crossLink "Container"}}{{/crossLink}}, {{#crossLink "Bitmap"}}{{/crossLink}}, and {{#crossLink "Shape"}}{{/crossLink}}.
* DisplayObject is the base class for all display classes in the EaselJS library. It defines the core properties and
* methods that are shared between all display objects, such as transformation properties (x, y, scaleX, scaleY, etc),
* caching, and mouse handlers.
* @class DisplayObject
* @extends EventDispatcher
* @constructor
**/
function DisplayObject() {
this.EventDispatcher_constructor();
// public properties:
/**
* The alpha (transparency) for this display object. 0 is fully transparent, 1 is fully opaque.
* @property alpha
* @type {Number}
* @default 1
**/
this.alpha = 1;
/**
* If a cache is active, this returns the canvas that holds the cached version of this display object. See {{#crossLink "cache"}}{{/crossLink}}
* for more information.
* @property cacheCanvas
* @type {HTMLCanvasElement | Object}
* @default null
* @readonly
**/
this.cacheCanvas = null;
/**
* Returns an ID number that uniquely identifies the current cache for this display object. This can be used to
* determine if the cache has changed since a previous check.
* @property cacheID
* @type {Number}
* @default 0
*/
this.cacheID = 0;
/**
* Unique ID for this display object. Makes display objects easier for some uses.
* @property id
* @type {Number}
* @default -1
**/
this.id = createjs.UID.get();
/**
* Indicates whether to include this object when running mouse interactions. Setting this to `false` for children
* of a {{#crossLink "Container"}}{{/crossLink}} will cause events on the Container to not fire when that child is
* clicked. Setting this property to `false` does not prevent the {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}
* method from returning the child.
*
* <strong>Note:</strong> In EaselJS 0.7.0, the mouseEnabled property will not work properly with nested Containers. Please
* check out the latest NEXT version in <a href="https://github.com/CreateJS/EaselJS/tree/master/lib">GitHub</a> for an updated version with this issue resolved. The fix will be
* provided in the next release of EaselJS.
* @property mouseEnabled
* @type {Boolean}
* @default true
**/
this.mouseEnabled = true;
/**
* If false, the tick will not run on this display object (or its children). This can provide some performance benefits.
* In addition to preventing the "tick" event from being dispatched, it will also prevent tick related updates
* on some display objects (ex. Sprite & MovieClip frame advancing, DOMElement visibility handling).
* @property tickEnabled
* @type Boolean
* @default true
**/
this.tickEnabled = true;
/**
* An optional name for this display object. Included in {{#crossLink "DisplayObject/toString"}}{{/crossLink}} . Useful for
* debugging.
* @property name
* @type {String}
* @default null
**/
this.name = null;
/**
* A reference to the {{#crossLink "Container"}}{{/crossLink}} or {{#crossLink "Stage"}}{{/crossLink}} object that
* contains this display object, or null if it has not been added
* to one.
* @property parent
* @final
* @type {Container}
* @default null
* @readonly
**/
this.parent = null;
/**
* The left offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate
* around its center, you would set regX and {{#crossLink "DisplayObject/regY:property"}}{{/crossLink}} to 50.
* @property regX
* @type {Number}
* @default 0
**/
this.regX = 0;
/**
* The y offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate around
* its center, you would set {{#crossLink "DisplayObject/regX:property"}}{{/crossLink}} and regY to 50.
* @property regY
* @type {Number}
* @default 0
**/
this.regY = 0;
/**
* The rotation in degrees for this display object.
* @property rotation
* @type {Number}
* @default 0
**/
this.rotation = 0;
/**
* The factor to stretch this display object horizontally. For example, setting scaleX to 2 will stretch the display
* object to twice its nominal width. To horizontally flip an object, set the scale to a negative number.
* @property scaleX
* @type {Number}
* @default 1
**/
this.scaleX = 1;
/**
* The factor to stretch this display object vertically. For example, setting scaleY to 0.5 will stretch the display
* object to half its nominal height. To vertically flip an object, set the scale to a negative number.
* @property scaleY
* @type {Number}
* @default 1
**/
this.scaleY = 1;
/**
* The factor to skew this display object horizontally.
* @property skewX
* @type {Number}
* @default 0
**/
this.skewX = 0;
/**
* The factor to skew this display object vertically.
* @property skewY
* @type {Number}
* @default 0
**/
this.skewY = 0;
/**
* A shadow object that defines the shadow to render on this display object. Set to `null` to remove a shadow. If
* null, this property is inherited from the parent container.
* @property shadow
* @type {Shadow}
* @default null
**/
this.shadow = null;
/**
* Indicates whether this display object should be rendered to the canvas and included when running the Stage
* {{#crossLink "Stage/getObjectsUnderPoint"}}{{/crossLink}} method.
* @property visible
* @type {Boolean}
* @default true
**/
this.visible = true;
/**
* The x (horizontal) position of the display object, relative to its parent.
* @property x
* @type {Number}
* @default 0
**/
this.x = 0;
/** The y (vertical) position of the display object, relative to its parent.
* @property y
* @type {Number}
* @default 0
**/
this.y = 0;
/**
* If set, defines the transformation for this display object, overriding all other transformation properties
* (x, y, rotation, scale, skew).
* @property transformMatrix
* @type {Matrix2D}
* @default null
**/
this.transformMatrix = null;
/**
* The composite operation indicates how the pixels of this display object will be composited with the elements
* behind it. If `null`, this property is inherited from the parent container. For more information, read the
* <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#compositing">
* whatwg spec on compositing</a>.
* @property compositeOperation
* @type {String}
* @default null
**/
this.compositeOperation = null;
/**
* Indicates whether the display object should be drawn to a whole pixel when
* {{#crossLink "Stage/snapToPixelEnabled"}}{{/crossLink}} is true. To enable/disable snapping on whole
* categories of display objects, set this value on the prototype (Ex. Text.prototype.snapToPixel = true).
* @property snapToPixel
* @type {Boolean}
* @default true
**/
this.snapToPixel = true;
/**
* An array of Filter objects to apply to this display object. Filters are only applied / updated when {{#crossLink "cache"}}{{/crossLink}}
* or {{#crossLink "updateCache"}}{{/crossLink}} is called on the display object, and only apply to the area that is
* cached.
* @property filters
* @type {Array}
* @default null
**/
this.filters = null;
/**
* A Shape instance that defines a vector mask (clipping path) for this display object. The shape's transformation
* will be applied relative to the display object's parent coordinates (as if it were a child of the parent).
* @property mask
* @type {Shape}
* @default null
*/
this.mask = null;
/**
* A display object that will be tested when checking mouse interactions or testing {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}.
* The hit area will have its transformation applied relative to this display object's coordinate space (as though
* the hit test object were a child of this display object and relative to its regX/Y). The hitArea will be tested
* using only its own `alpha` value regardless of the alpha value on the target display object, or the target's
* ancestors (parents).
*
* If set on a {{#crossLink "Container"}}{{/crossLink}}, children of the Container will not receive mouse events.
* This is similar to setting {{#crossLink "mouseChildren"}}{{/crossLink}} to false.
*
* Note that hitArea is NOT currently used by the `hitTest()` method, nor is it supported for {{#crossLink "Stage"}}{{/crossLink}}.
* @property hitArea
* @type {DisplayObject}
* @default null
*/
this.hitArea = null;
/**
* A CSS cursor (ex. "pointer", "help", "text", etc) that will be displayed when the user hovers over this display
* object. You must enable mouseover events using the {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}} method to
* use this property. Setting a non-null cursor on a Container will override the cursor set on its descendants.
* @property cursor
* @type {String}
* @default null
*/
this.cursor = null;
// private properties:
/**
* @property _cacheOffsetX
* @protected
* @type {Number}
* @default 0
**/
this._cacheOffsetX = 0;
/**
* @property _cacheOffsetY
* @protected
* @type {Number}
* @default 0
**/
this._cacheOffsetY = 0;
/**
* @property _filterOffsetX
* @protected
* @type {Number}
* @default 0
**/
this._filterOffsetX = 0;
/**
* @property _filterOffsetY
* @protected
* @type {Number}
* @default 0
**/
this._filterOffsetY = 0;
/**
* @property _cacheScale
* @protected
* @type {Number}
* @default 1
**/
this._cacheScale = 1;
/**
* @property _cacheDataURLID
* @protected
* @type {Number}
* @default 0
*/
this._cacheDataURLID = 0;
/**
* @property _cacheDataURL
* @protected
* @type {String}
* @default null
*/
this._cacheDataURL = null;
/**
* @property _props
* @protected
* @type {DisplayObject}
* @default null
**/
this._props = new createjs.DisplayProps();
/**
* @property _rectangle
* @protected
* @type {Rectangle}
* @default null
**/
this._rectangle = new createjs.Rectangle();
/**
* @property _bounds
* @protected
* @type {Rectangle}
* @default null
**/
this._bounds = null;
}
var p = createjs.extend(DisplayObject, createjs.EventDispatcher);
// TODO: deprecated
// p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
// static properties:
/**
* Listing of mouse event names. Used in _hasMouseEventListener.
* @property _MOUSE_EVENTS
* @protected
* @static
* @type {Array}
**/
DisplayObject._MOUSE_EVENTS = ["click","dblclick","mousedown","mouseout","mouseover","pressmove","pressup","rollout","rollover"];
/**
* Suppresses errors generated when using features like hitTest, mouse events, and {{#crossLink "getObjectsUnderPoint"}}{{/crossLink}}
* with cross domain content.
* @property suppressCrossDomainErrors
* @static
* @type {Boolean}
* @default false
**/
DisplayObject.suppressCrossDomainErrors = false;
/**
* @property _snapToPixelEnabled
* @protected
* @static
* @type {Boolean}
* @default false
**/
DisplayObject._snapToPixelEnabled = false; // stage.snapToPixelEnabled is temporarily copied here during a draw to provide global access.
/**
* @property _hitTestCanvas
* @type {HTMLCanvasElement | Object}
* @static
* @protected
**/
/**
* @property _hitTestContext
* @type {CanvasRenderingContext2D}
* @static
* @protected
**/
var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); // prevent errors on load in browsers without canvas.
if (canvas.getContext) {
DisplayObject._hitTestCanvas = canvas;
DisplayObject._hitTestContext = canvas.getContext("2d");
canvas.width = canvas.height = 1;
}
/**
* @property _nextCacheID
* @type {Number}
* @static
* @protected
**/
DisplayObject._nextCacheID = 1;
// events:
/**
* Dispatched when the user presses their left mouse button over the display object. See the
* {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event mousedown
* @since 0.6.0
*/
/**
* Dispatched when the user presses their left mouse button and then releases it while over the display object.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event click
* @since 0.6.0
*/
/**
* Dispatched when the user double clicks their left mouse button over this display object.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event dblclick
* @since 0.6.0
*/
/**
* Dispatched when the user's mouse enters this display object. This event must be enabled using
* {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollover:event"}}{{/crossLink}}.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event mouseover
* @since 0.6.0
*/
/**
* Dispatched when the user's mouse leaves this display object. This event must be enabled using
* {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollout:event"}}{{/crossLink}}.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event mouseout
* @since 0.6.0
*/
/**
* This event is similar to {{#crossLink "DisplayObject/mouseover:event"}}{{/crossLink}}, with the following
* differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an
* aggregate of their content.
*
* For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over
* shapeA and then directly on to shapeB. With a listener for {{#crossLink "mouseover:event"}}{{/crossLink}} on
* myContainer, two events would be received, each targeting a child element:<OL>
* <LI>when the mouse enters shapeA (target=shapeA)</LI>
* <LI>when the mouse enters shapeB (target=shapeB)</LI>
* </OL>
* However, with a listener for "rollover" instead, only a single event is received when the mouse first enters
* the aggregate myContainer content (target=myContainer).
*
* This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event rollover
* @since 0.7.0
*/
/**
* This event is similar to {{#crossLink "DisplayObject/mouseout:event"}}{{/crossLink}}, with the following
* differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an
* aggregate of their content.
*
* For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over
* shapeA, then directly on to shapeB, then off both. With a listener for {{#crossLink "mouseout:event"}}{{/crossLink}}
* on myContainer, two events would be received, each targeting a child element:<OL>
* <LI>when the mouse leaves shapeA (target=shapeA)</LI>
* <LI>when the mouse leaves shapeB (target=shapeB)</LI>
* </OL>
* However, with a listener for "rollout" instead, only a single event is received when the mouse leaves
* the aggregate myContainer content (target=myContainer).
*
* This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}.
* See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
* @event rollout
* @since 0.7.0
*/
/**
* After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressmove
* event will be generated on that object whenever the mouse moves until the mouse press is released. This can be
* useful for dragging and similar operations.
* @event pressmove
* @since 0.7.0
*/
/**
* After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressup event
* will be generated on that object when that mouse press is released. This can be useful for dragging and similar
* operations.
* @event pressup
* @since 0.7.0
*/
/**
* Dispatched when the display object is added to a parent container.
* @event added
*/
/**
* Dispatched when the display object is removed from its parent container.
* @event removed
*/
/**
* Dispatched on each display object on a stage whenever the stage updates. This occurs immediately before the
* rendering (draw) pass. When {{#crossLink "Stage/update"}}{{/crossLink}} is called, first all display objects on
* the stage dispatch the tick event, then all of the display objects are drawn to stage. Children will have their
* {{#crossLink "tick:event"}}{{/crossLink}} event dispatched in order of their depth prior to the event being
* dispatched on their parent.
* @event tick
* @param {Object} target The object that dispatched the event.
* @param {String} type The event type.
* @param {Array} params An array containing any arguments that were passed to the Stage.update() method. For
* example if you called stage.update("hello"), then the params would be ["hello"].
* @since 0.6.0
*/
// getter / setters:
/**
* Use the {{#crossLink "DisplayObject/stage:property"}}{{/crossLink}} property instead.
* @method getStage
* @return {Stage}
* @deprecated
**/
p.getStage = function() {
// uses dynamic access to avoid circular dependencies;
var o = this, _Stage = createjs["Stage"];
while (o.parent) { o = o.parent; }
if (o instanceof _Stage) { return o; }
return null;
};
/**
* Returns the Stage instance that this display object will be rendered on, or null if it has not been added to one.
* @property stage
* @type {Stage}
* @readonly
**/
try {
Object.defineProperties(p, {
stage: { get: p.getStage }
});
} catch (e) {}
// public methods:
/**
* Returns true or false indicating whether the display object would be visible if drawn to a canvas.
* This does not account for whether it would be visible within the boundaries of the stage.
*
* NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
* @method isVisible
* @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
**/
p.isVisible = function() {
return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0);
};
/**
* Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
* Returns <code>true</code> if the draw was handled (useful for overriding functionality).
*
* NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
* @method draw
* @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
* @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. For example,
* used for drawing the cache (to prevent it from simply drawing an existing cache back into itself).
* @return {Boolean}
**/
p.draw = function(ctx, ignoreCache) {
var cacheCanvas = this.cacheCanvas;
if (ignoreCache || !cacheCanvas) { return false; }
var scale = this._cacheScale;
ctx.drawImage(cacheCanvas, this._cacheOffsetX+this._filterOffsetX, this._cacheOffsetY+this._filterOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale);
return true;
};
/**
* Applies this display object's transformation, alpha, globalCompositeOperation, clipping path (mask), and shadow
* to the specified context. This is typically called prior to {{#crossLink "DisplayObject/draw"}}{{/crossLink}}.
* @method updateContext
* @param {CanvasRenderingContext2D} ctx The canvas 2D to update.
**/
p.updateContext = function(ctx) {
var o=this, mask=o.mask, mtx= o._props.matrix;
if (mask && mask.graphics && !mask.graphics.isEmpty()) {
mask.getMatrix(mtx);
ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
mask.graphics.drawAsPath(ctx);
ctx.clip();
mtx.invert();
ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
}
this.getMatrix(mtx);
var tx = mtx.tx, ty = mtx.ty;
if (DisplayObject._snapToPixelEnabled && o.snapToPixel) {
tx = tx + (tx < 0 ? -0.5 : 0.5) | 0;
ty = ty + (ty < 0 ? -0.5 : 0.5) | 0;
}
ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, tx, ty);
ctx.globalAlpha *= o.alpha;
if (o.compositeOperation) { ctx.globalCompositeOperation = o.compositeOperation; }
if (o.shadow) { this._applyShadow(ctx, o.shadow); }
};
/**
* Draws the display object into a new canvas, which is then used for subsequent draws. For complex content
* that does not change frequently (ex. a Container with many children that do not move, or a complex vector Shape),
* this can provide for much faster rendering because the content does not need to be re-rendered each tick. The
* cached display object can be moved, rotated, faded, etc freely, however if its content changes, you must
* manually update the cache by calling <code>updateCache()</code> or <code>cache()</code> again. You must specify
* the cache area via the x, y, w, and h parameters. This defines the rectangle that will be rendered and cached
* using this display object's coordinates.
*
* <h4>Example</h4>
* For example if you defined a Shape that drew a circle at 0, 0 with a radius of 25:
*
* var shape = new createjs.Shape();
* shape.graphics.beginFill("#ff0000").drawCircle(0, 0, 25);
* myShape.cache(-25, -25, 50, 50);
*
* Note that filters need to be defined <em>before</em> the cache is applied. Check out the {{#crossLink "Filter"}}{{/crossLink}}
* class for more information. Some filters (ex. BlurFilter) will not work as expected in conjunction with the scale param.
*
* Usually, the resulting cacheCanvas will have the dimensions width*scale by height*scale, however some filters (ex. BlurFilter)
* will add padding to the canvas dimensions.
*
* @method cache
* @param {Number} x The x coordinate origin for the cache region.
* @param {Number} y The y coordinate origin for the cache region.
* @param {Number} width The width of the cache region.
* @param {Number} height The height of the cache region.
* @param {Number} [scale=1] The scale at which the cache will be created. For example, if you cache a vector shape using
* myShape.cache(0,0,100,100,2) then the resulting cacheCanvas will be 200x200 px. This lets you scale and rotate
* cached elements with greater fidelity. Default is 1.
**/
p.cache = function(x, y, width, height, scale) {
// draw to canvas.
scale = scale||1;
if (!this.cacheCanvas) { this.cacheCanvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); }
this._cacheWidth = width;
this._cacheHeight = height;
this._cacheOffsetX = x;
this._cacheOffsetY = y;
this._cacheScale = scale;
this.updateCache();
};
/**
* Redraws the display object to its cache. Calling updateCache without an active cache will throw an error.
* If compositeOperation is null the current cache will be cleared prior to drawing. Otherwise the display object
* will be drawn over the existing cache using the specified compositeOperation.
*
* <h4>Example</h4>
* Clear the current graphics of a cached shape, draw some new instructions, and then update the cache. The new line
* will be drawn on top of the old one.
*
* // Not shown: Creating the shape, and caching it.
* shapeInstance.clear();
* shapeInstance.setStrokeStyle(3).beginStroke("#ff0000").moveTo(100, 100).lineTo(200,200);
* shapeInstance.updateCache();
*
* @method updateCache
* @param {String} compositeOperation The compositeOperation to use, or null to clear the cache and redraw it.
* <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#compositing">
* whatwg spec on compositing</a>.
**/
p.updateCache = function(compositeOperation) {
var cacheCanvas = this.cacheCanvas;
if (!cacheCanvas) { throw "cache() must be called before updateCache()"; }
var scale = this._cacheScale, offX = this._cacheOffsetX*scale, offY = this._cacheOffsetY*scale;
var w = this._cacheWidth, h = this._cacheHeight, ctx = cacheCanvas.getContext("2d");
var fBounds = this._getFilterBounds();
offX += (this._filterOffsetX = fBounds.x);
offY += (this._filterOffsetY = fBounds.y);
w = Math.ceil(w*scale) + fBounds.width;
h = Math.ceil(h*scale) + fBounds.height;
if (w != cacheCanvas.width || h != cacheCanvas.height) {
// TODO: it would be nice to preserve the content if there is a compositeOperation.
cacheCanvas.width = w;
cacheCanvas.height = h;
} else if (!compositeOperation) {
ctx.clearRect(0, 0, w+1, h+1);
}
ctx.save();
ctx.globalCompositeOperation = compositeOperation;
ctx.setTransform(scale, 0, 0, scale, -offX, -offY);
this.draw(ctx, true);
// TODO: filters and cache scale don't play well together at present.
this._applyFilters();
ctx.restore();
this.cacheID = DisplayObject._nextCacheID++;
};
/**
* Clears the current cache. See {{#crossLink "DisplayObject/cache"}}{{/crossLink}} for more information.
* @method uncache
**/
p.uncache = function() {
this._cacheDataURL = this.cacheCanvas = null;
this.cacheID = this._cacheOffsetX = this._cacheOffsetY = this._filterOffsetX = this._filterOffsetY = 0;
this._cacheScale = 1;
};
/**
* Returns a data URL for the cache, or null if this display object is not cached.
* Uses cacheID to ensure a new data URL is not generated if the cache has not changed.
* @method getCacheDataURL
* @return {String} The image data url for the cache.
**/
p.getCacheDataURL = function() {
if (!this.cacheCanvas) { return null; }
if (this.cacheID != this._cacheDataURLID) { this._cacheDataURL = this.cacheCanvas.toDataURL(); }
return this._cacheDataURL;
};
/**
* Transforms the specified x and y position from the coordinate space of the display object
* to the global (stage) coordinate space. For example, this could be used to position an HTML label
* over a specific point on a nested display object. Returns a Point instance with x and y properties
* correlating to the transformed coordinates on the stage.
*
* <h4>Example</h4>
*
* displayObject.x = 300;
* displayObject.y = 200;
* stage.addChild(displayObject);
* var point = displayObject.localToGlobal(100, 100);
* // Results in x=400, y=300
*
* @method localToGlobal
* @param {Number} x The x position in the source display object to transform.
* @param {Number} y The y position in the source display object to transform.
* @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
* @return {Point} A Point instance with x and y properties correlating to the transformed coordinates
* on the stage.
**/
p.localToGlobal = function(x, y, pt) {
return this.getConcatenatedMatrix(this._props.matrix).transformPoint(x,y, pt||new createjs.Point());
};
/**
* Transforms the specified x and y position from the global (stage) coordinate space to the
* coordinate space of the display object. For example, this could be used to determine
* the current mouse position within the display object. Returns a Point instance with x and y properties
* correlating to the transformed position in the display object's coordinate space.
*
* <h4>Example</h4>
*
* displayObject.x = 300;
* displayObject.y = 200;
* stage.addChild(displayObject);
* var point = displayObject.globalToLocal(100, 100);
* // Results in x=-200, y=-100
*
* @method globalToLocal
* @param {Number} x The x position on the stage to transform.
* @param {Number} y The y position on the stage to transform.
* @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
* @return {Point} A Point instance with x and y properties correlating to the transformed position in the
* display object's coordinate space.
**/
p.globalToLocal = function(x, y, pt) {
return this.getConcatenatedMatrix(this._props.matrix).invert().transformPoint(x,y, pt||new createjs.Point());
};
/**
* Transforms the specified x and y position from the coordinate space of this display object to the coordinate
* space of the target display object. Returns a Point instance with x and y properties correlating to the
* transformed position in the target's coordinate space. Effectively the same as using the following code with
* {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}.
*
* var pt = this.localToGlobal(x, y);
* pt = target.globalToLocal(pt.x, pt.y);
*
* @method localToLocal
* @param {Number} x The x position in the source display object to transform.
* @param {Number} y The y position on the source display object to transform.
* @param {DisplayObject} target The target display object to which the coordinates will be transformed.
* @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
* @return {Point} Returns a Point instance with x and y properties correlating to the transformed position
* in the target's coordinate space.
**/
p.localToLocal = function(x, y, target, pt) {
pt = this.localToGlobal(x, y, pt);
return target.globalToLocal(pt.x, pt.y, pt);
};
/**
* Shortcut method to quickly set the transform properties on the display object. All parameters are optional.
* Omitted parameters will have the default value set.
*
* <h4>Example</h4>
*
* displayObject.setTransform(100, 100, 2, 2);
*
* @method setTransform
* @param {Number} [x=0] The horizontal translation (x position) in pixels
* @param {Number} [y=0] The vertical translation (y position) in pixels
* @param {Number} [scaleX=1] The horizontal scale, as a percentage of 1
* @param {Number} [scaleY=1] the vertical scale, as a percentage of 1
* @param {Number} [rotation=0] The rotation, in degrees
* @param {Number} [skewX=0] The horizontal skew factor
* @param {Number} [skewY=0] The vertical skew factor
* @param {Number} [regX=0] The horizontal registration point in pixels
* @param {Number} [regY=0] The vertical registration point in pixels
* @return {DisplayObject} Returns this instance. Useful for chaining commands.
* @chainable
*/
p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
this.x = x || 0;
this.y = y || 0;
this.scaleX = scaleX == null ? 1 : scaleX;
this.scaleY = scaleY == null ? 1 : scaleY;
this.rotation = rotation || 0;
this.skewX = skewX || 0;
this.skewY = skewY || 0;
this.regX = regX || 0;
this.regY = regY || 0;
return this;
};
/**
* Returns a matrix based on this object's current transform.
* @method getMatrix
* @param {Matrix2D} matrix Optional. A Matrix2D object to populate with the calculated values. If null, a new
* Matrix object is returned.
* @return {Matrix2D} A matrix representing this display object's transform.
**/
p.getMatrix = function(matrix) {
var o = this, mtx = matrix&&matrix.identity() || new createjs.Matrix2D();
return o.transformMatrix ? mtx.copy(o.transformMatrix) : mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY);
};
/**
* Generates a Matrix2D object representing the combined transform of the display object and all of its
* parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}). This can
* be used to transform positions between coordinate spaces, such as with {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}}
* and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}.
* @method getConcatenatedMatrix
* @param {Matrix2D} [matrix] A {{#crossLink "Matrix2D"}}{{/crossLink}} object to populate with the calculated values.
* If null, a new Matrix2D object is returned.
* @return {Matrix2D} The combined matrix.
**/
p.getConcatenatedMatrix = function(matrix) {
var o = this, mtx = this.getMatrix(matrix);
while (o = o.parent) {
mtx.prependMatrix(o.getMatrix(o._props.matrix));
}
return mtx;
};
/**
* Generates a DisplayProps object representing the combined display properties of the object and all of its
* parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}).
* @method getConcatenatedDisplayProps
* @param {DisplayProps} [props] A {{#crossLink "DisplayProps"}}{{/crossLink}} object to populate with the calculated values.
* If null, a new DisplayProps object is returned.
* @return {DisplayProps} The combined display properties.
**/
p.getConcatenatedDisplayProps = function(props) {
props = props ? props.identity() : new createjs.DisplayProps();
var o = this, mtx = o.getMatrix(props.matrix);
do {
props.prepend(o.visible, o.alpha, o.shadow, o.compositeOperation);
// we do this to avoid problems with the matrix being used for both operations when o._props.matrix is passed in as the props param.
// this could be simplified (ie. just done as part of the prepend above) if we switched to using a pool.
if (o != this) { mtx.prependMatrix(o.getMatrix(o._props.matrix)); }
} while (o = o.parent);
return props;
};
/**
* Tests whether the display object intersects the specified point in <em>local</em> coordinates (ie. draws a pixel
* with alpha > 0 at the specified position). This ignores the alpha, shadow, hitArea, mask, and compositeOperation
* of the display object.
*
* <h4>Example</h4>
*
* var myShape = new createjs.Shape();
* myShape.graphics.beginFill("red").drawRect(100, 100, 20, 50);
*
* console.log(myShape.hitTest(10,10); // false
* console.log(myShape.hitTest(110, 25); // true
*
* Note that to use Stage coordinates (such as {{#crossLink "Stage/mouseX:property"}}{{/crossLink}}), they must
* first be converted to local coordinates:
*
* stage.addEventListener("stagemousedown", handleMouseDown);
* function handleMouseDown(event) {
* var p = myShape.globalToLocal(stage.mouseX, stage.mouseY);
* var hit = myShape.hitTest(p.x, p.y);
* }
*
* Shape-to-shape collision is not currently supported by EaselJS.
*
* @method hitTest
* @param {Number} x The x position to check in the display object's local coordinates.
* @param {Number} y The y position to check in the display object's local coordinates.
* @return {Boolean} A Boolean indicating whether a visible portion of the DisplayObject intersect the specified
* local Point.
*/
p.hitTest = function(x, y) {
var ctx = DisplayObject._hitTestContext;
ctx.setTransform(1, 0, 0, 1, -x, -y);
this.draw(ctx);
var hit = this._testHit(ctx);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, 2, 2);
return hit;
};
/**
* Provides a chainable shortcut method for setting a number of properties on the instance.
*
* <h4>Example</h4>
*
* var myGraphics = new createjs.Graphics().beginFill("#ff0000").drawCircle(0, 0, 25);
* var shape = stage.addChild(new createjs.Shape()).set({graphics:myGraphics, x:100, y:100, alpha:0.5});
*
* @method set
* @param {Object} props A generic object containing properties to copy to the DisplayObject instance.
* @return {DisplayObject} Returns the instance the method is called on (useful for chaining calls.)
* @chainable
*/
p.set = function(props) {
for (var n in props) { this[n] = props[n]; }
return this;
};
/**
* Returns a rectangle representing this object's bounds in its local coordinate system (ie. with no transformation).
* Objects that have been cached will return the bounds of the cache.
*
* Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use
* {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container
* bounds.
*
* <table>
* <tr><td><b>All</b></td><td>
* All display objects support setting bounds manually using setBounds(). Likewise, display objects that
* have been cached using cache() will return the bounds of their cache. Manual and cache bounds will override
* the automatic calculations listed below.
* </td></tr>
* <tr><td><b>Bitmap</b></td><td>
* Returns the width and height of the sourceRect (if specified) or image, extending from (x=0,y=0).
* </td></tr>
* <tr><td><b>Sprite</b></td><td>
* Returns the bounds of the current frame. May have non-zero x/y if a frame registration point was specified
* in the spritesheet data. See also {{#crossLink "SpriteSheet/getFrameBounds"}}{{/crossLink}}
* </td></tr>
* <tr><td><b>Container</b></td><td>
* Returns the aggregate (combined) bounds of all children that return a non-null value from getBounds().
* </td></tr>
* <tr><td><b>Shape</b></td><td>
* Does not currently support automatic bounds calculations. Use setBounds() to manually define bounds.
* </td></tr>
* <tr><td><b>Text</b></td><td>
* Returns approximate bounds. Horizontal values (x/width) are quite accurate, but vertical values (y/height) are
* not, especially when using textBaseline values other than "top".
* </td></tr>
* <tr><td><b>BitmapText</b></td><td>
* Returns approximate bounds. Values will be more accurate if spritesheet frame registration points are close
* to (x=0,y=0).
* </td></tr>
* </table>
*
* Bounds can be expensive to calculate for some objects (ex. text, or containers with many children), and
* are recalculated each time you call getBounds(). You can prevent recalculation on static objects by setting the
* bounds explicitly:
*
* var bounds = obj.getBounds();
* obj.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
* // getBounds will now use the set values, instead of recalculating
*
* To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its
* values if you need to retain it.
*
* var myBounds = obj.getBounds().clone();
* // OR:
* myRect.copy(obj.getBounds());
*
* @method getBounds
* @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this
* object.
**/
p.getBounds = function() {
if (this._bounds) { return this._rectangle.copy(this._bounds); }
var cacheCanvas = this.cacheCanvas;
if (cacheCanvas) {
var scale = this._cacheScale;
return this._rectangle.setValues(this._cacheOffsetX, this._cacheOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale);
}
return null;
};
/**
* Returns a rectangle representing this object's bounds in its parent's coordinate system (ie. with transformations applied).
* Objects that have been cached will return the transformed bounds of the cache.
*
* Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use
* {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container
* bounds.
*
* To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its
* values if you need to retain it.
*
* Container instances calculate aggregate bounds for all children that return bounds via getBounds.
* @method getTransformedBounds
* @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this object.
**/
p.getTransformedBounds = function() {
return this._getBounds();
};
/**
* Allows you to manually specify the bounds of an object that either cannot calculate their own bounds (ex. Shape &
* Text) for future reference, or so the object can be included in Container bounds. Manually set bounds will always
* override calculated bounds.
*
* The bounds should be specified in the object's local (untransformed) coordinates. For example, a Shape instance
* with a 25px radius circle centered at 0,0 would have bounds of (-25, -25, 50, 50).
* @method setBounds
* @param {Number} x The x origin of the bounds. Pass null to remove the manual bounds.
* @param {Number} y The y origin of the bounds.
* @param {Number} width The width of the bounds.
* @param {Number} height The height of the bounds.
**/
p.setBounds = function(x, y, width, height) {
if (x == null) { this._bounds = x; }
this._bounds = (this._bounds || new createjs.Rectangle()).setValues(x, y, width, height);
};
/**
* Returns a clone of this DisplayObject. Some properties that are specific to this instance's current context are
* reverted to their defaults (for example .parent). Caches are not maintained across clones, and some elements
* are copied by reference (masks, individual filter instances, hit area)
* @method clone
* @return {DisplayObject} A clone of the current DisplayObject instance.
**/
p.clone = function() {
return this._cloneProps(new DisplayObject());
};
/**
* Returns a string representation of this object.
* @method toString
* @return {String} a string representation of the instance.
**/
p.toString = function() {
return "[DisplayObject (name="+ this.name +")]";
};
// private methods:
// separated so it can be used more easily in subclasses:
/**
* @method _cloneProps
* @param {DisplayObject} o The DisplayObject instance which will have properties from the current DisplayObject
* instance copied into.
* @return {DisplayObject} o
* @protected
**/
p._cloneProps = function(o) {
o.alpha = this.alpha;
o.mouseEnabled = this.mouseEnabled;
o.tickEnabled = this.tickEnabled;
o.name = this.name;
o.regX = this.regX;
o.regY = this.regY;
o.rotation = this.rotation;
o.scaleX = this.scaleX;
o.scaleY = this.scaleY;
o.shadow = this.shadow;
o.skewX = this.skewX;
o.skewY = this.skewY;
o.visible = this.visible;
o.x = this.x;
o.y = this.y;
o.compositeOperation = this.compositeOperation;
o.snapToPixel = this.snapToPixel;
o.filters = this.filters==null?null:this.filters.slice(0);
o.mask = this.mask;
o.hitArea = this.hitArea;
o.cursor = this.cursor;
o._bounds = this._bounds;
return o;
};
/**
* @method _applyShadow
* @protected
* @param {CanvasRenderingContext2D} ctx
* @param {Shadow} shadow
**/
p._applyShadow = function(ctx, shadow) {
shadow = shadow || Shadow.identity;
ctx.shadowColor = shadow.color;
ctx.shadowOffsetX = shadow.offsetX;
ctx.shadowOffsetY = shadow.offsetY;
ctx.shadowBlur = shadow.blur;
};
/**
* @method _tick
* @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
* @protected
**/
p._tick = function(evtObj) {
// because tick can be really performance sensitive, check for listeners before calling dispatchEvent.
var ls = this._listeners;
if (ls && ls["tick"]) {
// reset & reuse the event object to avoid construction / GC costs:
evtObj.target = null;
evtObj.propagationStopped = evtObj.immediatePropagationStopped = false;
this.dispatchEvent(evtObj);
}
};
/**
* @method _testHit
* @protected
* @param {CanvasRenderingContext2D} ctx
* @return {Boolean}
**/
p._testHit = function(ctx) {
try {
var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
} catch (e) {
if (!DisplayObject.suppressCrossDomainErrors) {
throw "An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images.";
}
}
return hit;
};
/**
* @method _applyFilters
* @protected
**/
p._applyFilters = function() {
if (!this.filters || this.filters.length == 0 || !this.cacheCanvas) { return; }
var l = this.filters.length;
var ctx = this.cacheCanvas.getContext("2d");
var w = this.cacheCanvas.width;
var h = this.cacheCanvas.height;
for (var i=0; i<l; i++) {
this.filters[i].applyFilter(ctx, 0, 0, w, h);
}
};
/**
* @method _getFilterBounds
* @return {Rectangle}
* @protected
**/
p._getFilterBounds = function(rect) {
var l, filters = this.filters, bounds = this._rectangle.setValues(0,0,0,0);
if (!filters || !(l=filters.length)) { return bounds; }
for (var i=0; i<l; i++) {
var f = this.filters[i];
f.getBounds&&f.getBounds(bounds);
}
return bounds;
};
/**
* @method _getBounds
* @param {Matrix2D} matrix
* @param {Boolean} ignoreTransform If true, does not apply this object's transform.
* @return {Rectangle}
* @protected
**/
p._getBounds = function(matrix, ignoreTransform){
return this._transformBounds(this.getBounds(), matrix, ignoreTransform);
};
/**
* @method _transformBounds
* @param {Rectangle} bounds
* @param {Matrix2D} matrix
* @param {Boolean} ignoreTransform
* @return {Rectangle}
* @protected
**/
p._transformBounds = function(bounds, matrix, ignoreTransform) {
if (!bounds) { return bounds; }
var x = bounds.x, y = bounds.y, width = bounds.width, height = bounds.height, mtx = this._props.matrix;
mtx = ignoreTransform ? mtx.identity() : this.getMatrix(mtx);
if (x || y) { mtx.appendTransform(0,0,1,1,0,0,0,-x,-y); } // TODO: simplify this.
if (matrix) { mtx.prependMatrix(matrix); }
var x_a = width*mtx.a, x_b = width*mtx.b;
var y_c = height*mtx.c, y_d = height*mtx.d;
var tx = mtx.tx, ty = mtx.ty;
var minX = tx, maxX = tx, minY = ty, maxY = ty;
if ((x = x_a + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; }
if ((x = x_a + y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; }
if ((x = y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; }
if ((y = x_b + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
if ((y = x_b + y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
if ((y = y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
return bounds.setValues(minX, minY, maxX-minX, maxY-minY);
};
/**
* Indicates whether the display object has any mouse event listeners or a cursor.
* @method _isMouseOpaque
* @return {Boolean}
* @protected
**/
p._hasMouseEventListener = function() {
var evts = DisplayObject._MOUSE_EVENTS;
for (var i= 0, l=evts.length; i<l; i++) {
if (this.hasEventListener(evts[i])) { return true; }
}
return !!this.cursor;
};
createjs.DisplayObject = createjs.promote(DisplayObject, "EventDispatcher");
}());