Files
Foundry-VTT-Docker/resources/app/node_modules/@pixi/display/lib/DisplayObject.js
2025-01-04 00:34:03 +01:00

366 lines
15 KiB
JavaScript

"use strict";
var core = require("@pixi/core"), Bounds = require("./Bounds.js");
class DisplayObject extends core.utils.EventEmitter {
constructor() {
super(), this.tempDisplayObjectParent = null, this.transform = new core.Transform(), this.alpha = 1, this.visible = !0, this.renderable = !0, this.cullable = !1, this.cullArea = null, this.parent = null, this.worldAlpha = 1, this._lastSortedIndex = 0, this._zIndex = 0, this.filterArea = null, this.filters = null, this._enabledFilters = null, this._bounds = new Bounds.Bounds(), this._localBounds = null, this._boundsID = 0, this._boundsRect = null, this._localBoundsRect = null, this._mask = null, this._maskRefCount = 0, this._destroyed = !1, this.isSprite = !1, this.isMask = !1;
}
/**
* Mixes all enumerable properties and methods from a source object to DisplayObject.
* @param source - The source of properties and methods to mix in.
*/
static mixin(source) {
const keys = Object.keys(source);
for (let i = 0; i < keys.length; ++i) {
const propertyName = keys[i];
Object.defineProperty(
DisplayObject.prototype,
propertyName,
Object.getOwnPropertyDescriptor(source, propertyName)
);
}
}
/**
* Fired when this DisplayObject is added to a Container.
* @instance
* @event added
* @param {PIXI.Container} container - The container added to.
*/
/**
* Fired when this DisplayObject is removed from a Container.
* @instance
* @event removed
* @param {PIXI.Container} container - The container removed from.
*/
/**
* Fired when this DisplayObject is destroyed. This event is emitted once
* destroy is finished.
* @instance
* @event destroyed
*/
/** Readonly flag for destroyed display objects. */
get destroyed() {
return this._destroyed;
}
/** Recursively updates transform of all objects from the root to this one internal function for toLocal() */
_recursivePostUpdateTransform() {
this.parent ? (this.parent._recursivePostUpdateTransform(), this.transform.updateTransform(this.parent.transform)) : this.transform.updateTransform(this._tempDisplayObjectParent.transform);
}
/** Updates the object transform for rendering. TODO - Optimization pass! */
updateTransform() {
this._boundsID++, this.transform.updateTransform(this.parent.transform), this.worldAlpha = this.alpha * this.parent.worldAlpha;
}
/**
* Calculates and returns the (world) bounds of the display object as a [Rectangle]{@link PIXI.Rectangle}.
*
* This method is expensive on containers with a large subtree (like the stage). This is because the bounds
* of a container depend on its children's bounds, which recursively causes all bounds in the subtree to
* be recalculated. The upside, however, is that calling `getBounds` once on a container will indeed update
* the bounds of all children (the whole subtree, in fact). This side effect should be exploited by using
* `displayObject._bounds.getRectangle()` when traversing through all the bounds in a scene graph. Otherwise,
* calling `getBounds` on each object in a subtree will cause the total cost to increase quadratically as
* its height increases.
*
* The transforms of all objects in a container's **subtree** and of all **ancestors** are updated.
* The world bounds of all display objects in a container's **subtree** will also be recalculated.
*
* The `_bounds` object stores the last calculation of the bounds. You can use to entirely skip bounds
* calculation if needed.
*
* ```js
* const lastCalculatedBounds = displayObject._bounds.getRectangle(optionalRect);
* ```
*
* Do know that usage of `getLocalBounds` can corrupt the `_bounds` of children (the whole subtree, actually). This
* is a known issue that has not been solved. See [getLocalBounds]{@link PIXI.DisplayObject#getLocalBounds} for more
* details.
*
* `getBounds` should be called with `skipUpdate` equal to `true` in a render() call. This is because the transforms
* are guaranteed to be update-to-date. In fact, recalculating inside a render() call may cause corruption in certain
* cases.
* @param skipUpdate - Setting to `true` will stop the transforms of the scene graph from
* being updated. This means the calculation returned MAY be out of date BUT will give you a
* nice performance boost.
* @param rect - Optional rectangle to store the result of the bounds calculation.
* @returns - The minimum axis-aligned rectangle in world space that fits around this object.
*/
getBounds(skipUpdate, rect) {
return skipUpdate || (this.parent ? (this._recursivePostUpdateTransform(), this.updateTransform()) : (this.parent = this._tempDisplayObjectParent, this.updateTransform(), this.parent = null)), this._bounds.updateID !== this._boundsID && (this.calculateBounds(), this._bounds.updateID = this._boundsID), rect || (this._boundsRect || (this._boundsRect = new core.Rectangle()), rect = this._boundsRect), this._bounds.getRectangle(rect);
}
/**
* Retrieves the local bounds of the displayObject as a rectangle object.
* @param rect - Optional rectangle to store the result of the bounds calculation.
* @returns - The rectangular bounding area.
*/
getLocalBounds(rect) {
rect || (this._localBoundsRect || (this._localBoundsRect = new core.Rectangle()), rect = this._localBoundsRect), this._localBounds || (this._localBounds = new Bounds.Bounds());
const transformRef = this.transform, parentRef = this.parent;
this.parent = null, this._tempDisplayObjectParent.worldAlpha = parentRef?.worldAlpha ?? 1, this.transform = this._tempDisplayObjectParent.transform;
const worldBounds = this._bounds, worldBoundsID = this._boundsID;
this._bounds = this._localBounds;
const bounds = this.getBounds(!1, rect);
return this.parent = parentRef, this.transform = transformRef, this._bounds = worldBounds, this._bounds.updateID += this._boundsID - worldBoundsID, bounds;
}
/**
* Calculates the global position of the display object.
* @param position - The world origin to calculate from.
* @param point - A Point object in which to store the value, optional
* (otherwise will create a new Point).
* @param skipUpdate - Should we skip the update transform.
* @returns - A point object representing the position of this object.
*/
toGlobal(position, point, skipUpdate = !1) {
return skipUpdate || (this._recursivePostUpdateTransform(), this.parent ? this.displayObjectUpdateTransform() : (this.parent = this._tempDisplayObjectParent, this.displayObjectUpdateTransform(), this.parent = null)), this.worldTransform.apply(position, point);
}
/**
* Calculates the local position of the display object relative to another point.
* @param position - The world origin to calculate from.
* @param from - The DisplayObject to calculate the global position from.
* @param point - A Point object in which to store the value, optional
* (otherwise will create a new Point).
* @param skipUpdate - Should we skip the update transform
* @returns - A point object representing the position of this object
*/
toLocal(position, from, point, skipUpdate) {
return from && (position = from.toGlobal(position, point, skipUpdate)), skipUpdate || (this._recursivePostUpdateTransform(), this.parent ? this.displayObjectUpdateTransform() : (this.parent = this._tempDisplayObjectParent, this.displayObjectUpdateTransform(), this.parent = null)), this.worldTransform.applyInverse(position, point);
}
/**
* Set the parent Container of this DisplayObject.
* @param container - The Container to add this DisplayObject to.
* @returns - The Container that this DisplayObject was added to.
*/
setParent(container) {
if (!container || !container.addChild)
throw new Error("setParent: Argument must be a Container");
return container.addChild(this), container;
}
/** Remove the DisplayObject from its parent Container. If the DisplayObject has no parent, do nothing. */
removeFromParent() {
this.parent?.removeChild(this);
}
/**
* Convenience function to set the position, scale, skew and pivot at once.
* @param x - The X position
* @param y - The Y position
* @param scaleX - The X scale value
* @param scaleY - The Y scale value
* @param rotation - The rotation
* @param skewX - The X skew value
* @param skewY - The Y skew value
* @param pivotX - The X pivot value
* @param pivotY - The Y pivot value
* @returns - The DisplayObject instance
*/
setTransform(x = 0, y = 0, scaleX = 1, scaleY = 1, rotation = 0, skewX = 0, skewY = 0, pivotX = 0, pivotY = 0) {
return this.position.x = x, this.position.y = y, this.scale.x = scaleX || 1, this.scale.y = scaleY || 1, this.rotation = rotation, this.skew.x = skewX, this.skew.y = skewY, this.pivot.x = pivotX, this.pivot.y = pivotY, this;
}
/**
* Base destroy method for generic display objects. This will automatically
* remove the display object from its parent Container as well as remove
* all current event listeners and internal references. Do not use a DisplayObject
* after calling `destroy()`.
* @param _options
*/
destroy(_options) {
this.removeFromParent(), this._destroyed = !0, this.transform = null, this.parent = null, this._bounds = null, this.mask = null, this.cullArea = null, this.filters = null, this.filterArea = null, this.hitArea = null, this.eventMode = "auto", this.interactiveChildren = !1, this.emit("destroyed"), this.removeAllListeners();
}
/**
* @protected
* @member {PIXI.Container}
*/
get _tempDisplayObjectParent() {
return this.tempDisplayObjectParent === null && (this.tempDisplayObjectParent = new TemporaryDisplayObject()), this.tempDisplayObjectParent;
}
/**
* Used in Renderer, cacheAsBitmap and other places where you call an `updateTransform` on root.
*
* ```js
* const cacheParent = elem.enableTempParent();
* elem.updateTransform();
* elem.disableTempParent(cacheParent);
* ```
* @returns - Current parent
*/
enableTempParent() {
const myParent = this.parent;
return this.parent = this._tempDisplayObjectParent, myParent;
}
/**
* Pair method for `enableTempParent`
* @param cacheParent - Actual parent of element
*/
disableTempParent(cacheParent) {
this.parent = cacheParent;
}
/**
* The position of the displayObject on the x axis relative to the local coordinates of the parent.
* An alias to position.x
*/
get x() {
return this.position.x;
}
set x(value) {
this.transform.position.x = value;
}
/**
* The position of the displayObject on the y axis relative to the local coordinates of the parent.
* An alias to position.y
*/
get y() {
return this.position.y;
}
set y(value) {
this.transform.position.y = value;
}
/**
* Current transform of the object based on world (parent) factors.
* @readonly
*/
get worldTransform() {
return this.transform.worldTransform;
}
/**
* Current transform of the object based on local factors: position, scale, other stuff.
* @readonly
*/
get localTransform() {
return this.transform.localTransform;
}
/**
* The coordinate of the object relative to the local coordinates of the parent.
* @since 4.0.0
*/
get position() {
return this.transform.position;
}
set position(value) {
this.transform.position.copyFrom(value);
}
/**
* The scale factors of this object along the local coordinate axes.
*
* The default scale is (1, 1).
* @since 4.0.0
*/
get scale() {
return this.transform.scale;
}
set scale(value) {
this.transform.scale.copyFrom(value);
}
/**
* The center of rotation, scaling, and skewing for this display object in its local space. The `position`
* is the projection of `pivot` in the parent's local space.
*
* By default, the pivot is the origin (0, 0).
* @since 4.0.0
*/
get pivot() {
return this.transform.pivot;
}
set pivot(value) {
this.transform.pivot.copyFrom(value);
}
/**
* The skew factor for the object in radians.
* @since 4.0.0
*/
get skew() {
return this.transform.skew;
}
set skew(value) {
this.transform.skew.copyFrom(value);
}
/**
* The rotation of the object in radians.
* 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees.
*/
get rotation() {
return this.transform.rotation;
}
set rotation(value) {
this.transform.rotation = value;
}
/**
* The angle of the object in degrees.
* 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees.
*/
get angle() {
return this.transform.rotation * core.RAD_TO_DEG;
}
set angle(value) {
this.transform.rotation = value * core.DEG_TO_RAD;
}
/**
* The zIndex of the displayObject.
*
* If a container has the sortableChildren property set to true, children will be automatically
* sorted by zIndex value; a higher value will mean it will be moved towards the end of the array,
* and thus rendered on top of other display objects within the same container.
* @see PIXI.Container#sortableChildren
*/
get zIndex() {
return this._zIndex;
}
set zIndex(value) {
this._zIndex !== value && (this._zIndex = value, this.parent && (this.parent.sortDirty = !0));
}
/**
* Indicates if the object is globally visible.
* @readonly
*/
get worldVisible() {
let item = this;
do {
if (!item.visible)
return !1;
item = item.parent;
} while (item);
return !0;
}
/**
* Sets a mask for the displayObject. A mask is an object that limits the visibility of an
* object to the shape of the mask applied to it. In PixiJS a regular mask must be a
* {@link PIXI.Graphics} or a {@link PIXI.Sprite} object. This allows for much faster masking in canvas as it
* utilities shape clipping. Furthermore, a mask of an object must be in the subtree of its parent.
* Otherwise, `getLocalBounds` may calculate incorrect bounds, which makes the container's width and height wrong.
* To remove a mask, set this property to `null`.
*
* For sprite mask both alpha and red channel are used. Black mask is the same as transparent mask.
* @example
* import { Graphics, Sprite } from 'pixi.js';
*
* const graphics = new Graphics();
* graphics.beginFill(0xFF3300);
* graphics.drawRect(50, 250, 100, 100);
* graphics.endFill();
*
* const sprite = new Sprite(texture);
* sprite.mask = graphics;
* @todo At the moment, CanvasRenderer doesn't support Sprite as mask.
*/
get mask() {
return this._mask;
}
set mask(value) {
if (this._mask !== value) {
if (this._mask) {
const maskObject = this._mask.isMaskData ? this._mask.maskObject : this._mask;
maskObject && (maskObject._maskRefCount--, maskObject._maskRefCount === 0 && (maskObject.renderable = !0, maskObject.isMask = !1));
}
if (this._mask = value, this._mask) {
const maskObject = this._mask.isMaskData ? this._mask.maskObject : this._mask;
maskObject && (maskObject._maskRefCount === 0 && (maskObject.renderable = !1, maskObject.isMask = !0), maskObject._maskRefCount++);
}
}
}
}
class TemporaryDisplayObject extends DisplayObject {
constructor() {
super(...arguments), this.sortDirty = null;
}
}
DisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform;
exports.DisplayObject = DisplayObject;
exports.TemporaryDisplayObject = TemporaryDisplayObject;
//# sourceMappingURL=DisplayObject.js.map