Extensions

Source: display/Item.js

import { noop } from "../../extensions/utils/noop";
import { Color } from "../attributes/Color";
import { ItemTransform } from "../attributes/ItemTransform";
import { Matrix3Utilities } from "../math/Matrix3Utilities";
import "../math/RectangleType";

/**
 * Item
 * @property {Item.Type} TYPE
 * @property {Array<number>} matrixCache
 * @property {Array<number>} colorCache
 * @property {boolean} interactive
 * @property {boolean} renderable
 * @property {ItemTransform} transform
 * @property {Color} color
 * @property {number} alpha
 * @property {boolean} transformUpdated
 * @property {boolean} colorUpdated
 * @property {function} callbackBeforeRender
 * @property {function} callbackAfterRender
 */
export class Item {
  /**
   * Creates an instance of Item.
   * @constructor
   */
  constructor() {
    this.RENDERING_TYPE = Item.RENDERING_TYPE;

    this.matrixCache = Matrix3Utilities.identity();
    this.colorCache = new Float32Array([1, 1, 1, 1]);
    this.transform = new this.$transformClass();
    this.color = new Color();
    this.alpha = 1;
    this.callbackBeforeRender = this.callbackAfterRender = noop;
    this.renderable = true;
    this.$bounds = { x: 0, y: 0, width: 0, height: 0 };
  }

  /**
   * Get StageContainer
   * @readonly
   * @type {StageContainer}
   */
  get stage() {
    return this.$parent ? this.$parent.stage : null;
  }

  /**
   * Set/Get parent
   * @type {Container}
   */
  get parent() {
    return this.$parent;
  }
  set parent(v) {
    this.$parent = v;
    this._parentChanged = true;
  }

  /**
   * <pre>
   *  Set/Get before render callback
   *    - It will be called before the Item rendered
   * </pre>
   * @type {function}
   */
  get callbackBeforeRender() {
    return this._callbackBeforeRender;
  }
  set callbackBeforeRender(v) {
    this._callbackBeforeRender = v ?? noop;
  }

  /**
   * <pre>
   *  Set/Get after render callback
   *    - It will be called after the Item rendered
   * </pre>
   * @type {function}
   */
  get callbackAfterRender() {
    return this._callbackAfterRender;
  }
  set callbackAfterRender(v) {
    this._callbackAfterRender = v ?? noop;
  }

  /**
   * <pre>
   *  Handle event
   *    - It can handle mouse events if the item is interactive and has [
   *      onPointerOver,
   *      onPointerOut,
   *      onPointerMove,
   *      onPointerDown,
   *      onPointerUp,
   *      onPointerClick
   *    ] function
   * </pre>
   * @param {*} event
   */
  callEventHandler(target, event) {
    if (this.interactive) {
      const callback = this["on" + event.type];
      callback && callback(this, target, event);
    }

    const { $parent } = this;
    $parent && $parent.callEventHandler(target, event);
  }

  /**
   * Destruct class
   */
  destruct() {
    this.remove();
  }

  /**
   * Remove Item from parent
   */
  remove() {
    const { $parent } = this;
    $parent && $parent.removeChild(this);
  }

  /**
   * Update color and transform values
   */
  update() {
    const { transform, color, $parent, _parentChanged } = this;

    this._parentChanged = false;

    color.update();

    this.colorUpdated = _parentChanged || color.updated || $parent.colorUpdated;

    if (this.colorUpdated) {
      const { colorCache } = this;
      const originalColorCache = color.cache;
      const parentColorCache = $parent.colorCache;

      colorCache[0] = parentColorCache[0] * originalColorCache[0];
      colorCache[1] = parentColorCache[1] * originalColorCache[1];
      colorCache[2] = parentColorCache[2] * originalColorCache[2];
      colorCache[3] = parentColorCache[3] * originalColorCache[3];
    }

    transform.update();

    this.transformUpdated = _parentChanged || transform.updated || $parent.transformUpdated;

    this.transformUpdated && Matrix3Utilities.transform(this.matrixCache, $parent.matrixCache, transform);
  }

  /**
   * @ignore
   */
  get $transformClass() {
    return ItemTransform;
  }
}

/**
 * Type "item"
 * @string
 */
Item.RENDERING_TYPE = "item";