{"version":3,"file":"Collection.min.mjs","names":[],"sources":["../../src/Collection.ts"],"sourcesContent":["import type { Constructor, TBBox } from './typedefs';\nimport { removeFromArray } from './util/internals/removeFromArray';\nimport { Point } from './Point';\nimport type { ActiveSelection } from './shapes/ActiveSelection';\nimport type { Group } from './shapes/Group';\nimport type { InteractiveFabricObject } from './shapes/Object/InteractiveObject';\nimport type { FabricObject } from './shapes/Object/FabricObject';\n\nexport const isCollection = (\n  fabricObject?: FabricObject,\n): fabricObject is Group | ActiveSelection => {\n  return !!fabricObject && Array.isArray((fabricObject as Group)._objects);\n};\n\nexport function createCollectionMixin<TBase extends Constructor>(Base: TBase) {\n  class Collection extends Base {\n    /**\n     * @type {FabricObject[]}\n     * @TODO needs to end up in the constructor too\n     */\n    _objects: FabricObject[] = [];\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    _onObjectAdded(object: FabricObject) {\n      // subclasses should override this method\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    _onObjectRemoved(object: FabricObject) {\n      // subclasses should override this method\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    _onStackOrderChanged(object: FabricObject) {\n      // subclasses should override this method\n    }\n\n    /**\n     * Adds objects to collection\n     * Objects should be instances of (or inherit from) FabricObject\n     * @param {...FabricObject[]} objects to add\n     * @returns {number} new array length\n     */\n    add(...objects: FabricObject[]): number {\n      const size = this._objects.push(...objects);\n      objects.forEach((object) => this._onObjectAdded(object));\n      return size;\n    }\n\n    /**\n     * Inserts an object into collection at specified index\n     * @param {number} index Index to insert object at\n     * @param {...FabricObject[]} objects Object(s) to insert\n     * @returns {number} new array length\n     */\n    insertAt(index: number, ...objects: FabricObject[]) {\n      this._objects.splice(index, 0, ...objects);\n      objects.forEach((object) => this._onObjectAdded(object));\n      return this._objects.length;\n    }\n\n    /**\n     * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n     * @private\n     * @param {...FabricObject[]} objects objects to remove\n     * @returns {FabricObject[]} removed objects\n     */\n    remove(...objects: FabricObject[]) {\n      const array = this._objects,\n        removed: FabricObject[] = [];\n      objects.forEach((object) => {\n        const index = array.indexOf(object);\n        // only call onObjectRemoved if an object was actually removed\n        if (index !== -1) {\n          array.splice(index, 1);\n          removed.push(object);\n          this._onObjectRemoved(object);\n        }\n      });\n      return removed;\n    }\n\n    /**\n     * Executes given function for each object in this group\n     * A simple shortcut for getObjects().forEach, before es6 was more complicated,\n     * now is just a shortcut.\n     * @param {Function} callback\n     *                   Callback invoked with current object as first argument,\n     *                   index - as second and an array of all objects - as third.\n     */\n    forEachObject(\n      callback: (\n        object: FabricObject,\n        index: number,\n        array: FabricObject[],\n      ) => any,\n    ) {\n      this.getObjects().forEach((object, index, objects) =>\n        callback(object, index, objects),\n      );\n    }\n\n    /**\n     * Returns an array of children objects of this instance\n     * @param {...String} [types] When specified, only objects of these types are returned\n     * @return {Array}\n     */\n    getObjects(...types: string[]) {\n      if (types.length === 0) {\n        return [...this._objects];\n      }\n      return this._objects.filter((o) => o.isType(...types));\n    }\n\n    /**\n     * Returns object at specified index\n     * @param {Number} index\n     * @return {Object} object at index\n     */\n    item(index: number) {\n      return this._objects[index];\n    }\n\n    /**\n     * Returns true if collection contains no objects\n     * @return {Boolean} true if collection is empty\n     */\n    isEmpty() {\n      return this._objects.length === 0;\n    }\n\n    /**\n     * Returns a size of a collection (i.e: length of an array containing its objects)\n     * @return {Number} Collection size\n     */\n    size() {\n      return this._objects.length;\n    }\n\n    /**\n     * Returns true if collection contains an object.\\\n     * **Prefer using {@link FabricObject#isDescendantOf} for performance reasons**\n     * instead of `a.contains(b)` use `b.isDescendantOf(a)`\n     * @param {Object} object Object to check against\n     * @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`\n     * @return {Boolean} `true` if collection contains an object\n     */\n    contains(object: FabricObject, deep?: boolean): boolean {\n      if (this._objects.includes(object)) {\n        return true;\n      } else if (deep) {\n        return this._objects.some(\n          (obj) =>\n            obj instanceof Collection &&\n            (obj as unknown as Collection).contains(object, true),\n        );\n      }\n      return false;\n    }\n\n    /**\n     * Returns number representation of a collection complexity\n     * @return {Number} complexity\n     */\n    complexity() {\n      return this._objects.reduce((memo, current) => {\n        memo += current.complexity ? current.complexity() : 0;\n        return memo;\n      }, 0);\n    }\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the bottom of the stack of drawn objects\n     * @param {fabric.Object} object Object to send to back\n     * @returns {boolean} true if change occurred\n     */\n    sendObjectToBack(object: FabricObject) {\n      if (!object || object === this._objects[0]) {\n        return false;\n      }\n      removeFromArray(this._objects, object);\n      this._objects.unshift(object);\n      this._onStackOrderChanged(object);\n      return true;\n    }\n\n    /**\n     * Moves an object or the objects of a multiple selection\n     * to the top of the stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @returns {boolean} true if change occurred\n     */\n    bringObjectToFront(object: FabricObject) {\n      if (!object || object === this._objects[this._objects.length - 1]) {\n        return false;\n      }\n      removeFromArray(this._objects, object);\n      this._objects.push(object);\n      this._onStackOrderChanged(object);\n      return true;\n    }\n\n    /**\n     * Moves an object or a selection down in stack of drawn objects\n     * An optional parameter, `intersecting` allows to move the object in behind\n     * the first intersecting object. Where intersection is calculated with\n     * bounding box. If no intersection is found, there will not be change in the\n     * stack.\n     * @param {fabric.Object} object Object to send\n     * @param {boolean} [intersecting] If `true`, send object behind next lower intersecting object\n     * @returns {boolean} true if change occurred\n     */\n    sendObjectBackwards(object: FabricObject, intersecting?: boolean) {\n      if (!object) {\n        return false;\n      }\n      const idx = this._objects.indexOf(object);\n      if (idx !== 0) {\n        // if object is not on the bottom of stack\n        const newIdx = this.findNewLowerIndex(object, idx, intersecting);\n        removeFromArray(this._objects, object);\n        this._objects.splice(newIdx, 0, object);\n        this._onStackOrderChanged(object);\n        return true;\n      }\n      return false;\n    }\n\n    /**\n     * Moves an object or a selection up in stack of drawn objects\n     * An optional parameter, intersecting allows to move the object in front\n     * of the first intersecting object. Where intersection is calculated with\n     * bounding box. If no intersection is found, there will not be change in the\n     * stack.\n     * @param {fabric.Object} object Object to send\n     * @param {boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n     * @returns {boolean} true if change occurred\n     */\n    bringObjectForward(object: FabricObject, intersecting?: boolean) {\n      if (!object) {\n        return false;\n      }\n      const idx = this._objects.indexOf(object);\n      if (idx !== this._objects.length - 1) {\n        // if object is not on top of stack (last item in an array)\n        const newIdx = this.findNewUpperIndex(object, idx, intersecting);\n        removeFromArray(this._objects, object);\n        this._objects.splice(newIdx, 0, object);\n        this._onStackOrderChanged(object);\n        return true;\n      }\n      return false;\n    }\n\n    /**\n     * Moves an object to specified level in stack of drawn objects\n     * @param {fabric.Object} object Object to send\n     * @param {number} index Position to move to\n     * @returns {boolean} true if change occurred\n     */\n    moveObjectTo(object: FabricObject, index: number) {\n      if (object === this._objects[index]) {\n        return false;\n      }\n      removeFromArray(this._objects, object);\n      this._objects.splice(index, 0, object);\n      this._onStackOrderChanged(object);\n      return true;\n    }\n\n    findNewLowerIndex(\n      object: FabricObject,\n      idx: number,\n      intersecting?: boolean,\n    ) {\n      let newIdx;\n\n      if (intersecting) {\n        newIdx = idx;\n        // traverse down the stack looking for the nearest intersecting object\n        for (let i = idx - 1; i >= 0; --i) {\n          if (object.isOverlapping(this._objects[i])) {\n            newIdx = i;\n            break;\n          }\n        }\n      } else {\n        newIdx = idx - 1;\n      }\n\n      return newIdx;\n    }\n\n    findNewUpperIndex(\n      object: FabricObject,\n      idx: number,\n      intersecting?: boolean,\n    ) {\n      let newIdx;\n\n      if (intersecting) {\n        newIdx = idx;\n        // traverse up the stack looking for the nearest intersecting object\n        for (let i = idx + 1; i < this._objects.length; ++i) {\n          if (object.isOverlapping(this._objects[i])) {\n            newIdx = i;\n            break;\n          }\n        }\n      } else {\n        newIdx = idx + 1;\n      }\n\n      return newIdx;\n    }\n\n    /**\n     * Given a bounding box, return all the objects of the collection that are contained in the bounding box.\n     * If `includeIntersecting` is true, return also the objects that intersect the bounding box as well.\n     * This is meant to work with selection. Is not a generic method.\n     * @param {TBBox} bbox a bounding box in scene coordinates\n     * @param {{ includeIntersecting?: boolean }} options an object with includeIntersecting\n     * @returns array of objects contained in the bounding box, ordered from top to bottom stacking wise\n     */\n    collectObjects(\n      { left, top, width, height }: TBBox,\n      { includeIntersecting = true }: { includeIntersecting?: boolean } = {},\n    ) {\n      const objects: InteractiveFabricObject[] = [],\n        tl = new Point(left, top),\n        br = tl.add(new Point(width, height));\n\n      // we iterate reverse order to collect top first in case of click.\n      for (let i = this._objects.length - 1; i >= 0; i--) {\n        const object = this._objects[i] as unknown as InteractiveFabricObject;\n        if (\n          object.selectable &&\n          object.visible &&\n          ((includeIntersecting && object.intersectsWithRect(tl, br)) ||\n            object.isContainedWithinRect(tl, br) ||\n            (includeIntersecting && object.containsPoint(tl)) ||\n            (includeIntersecting && object.containsPoint(br)))\n        ) {\n          objects.push(object);\n        }\n      }\n\n      return objects;\n    }\n  }\n\n  // https://github.com/microsoft/TypeScript/issues/32080\n  return Collection;\n}\n"],"mappings":"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"}