{"version":3,"file":"Collection.min.mjs","sources":["../../src/Collection.ts"],"sourcesContent":["import type { Constructor, TBBox } from './typedefs';\nimport { removeFromArray } from './util/internals';\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 as typeof Collection & TBase;\n}\n"],"names":["isCollection","fabricObject","Array","isArray","_objects","createCollectionMixin","Base","Collection","constructor","super","arguments","_defineProperty","_onObjectAdded","object","_onObjectRemoved","_onStackOrderChanged","add","_len","length","objects","_key","size","this","push","forEach","insertAt","index","_len2","_key2","splice","remove","array","removed","_len3","_key3","indexOf","forEachObject","callback","getObjects","_len4","types","_key4","filter","o","isType","item","isEmpty","contains","deep","includes","some","obj","complexity","reduce","memo","current","sendObjectToBack","removeFromArray","unshift","bringObjectToFront","sendObjectBackwards","intersecting","idx","newIdx","findNewLowerIndex","bringObjectForward","findNewUpperIndex","moveObjectTo","i","isOverlapping","collectObjects","_ref","left","top","width","height","includeIntersecting","undefined","tl","Point","br","selectable","visible","intersectsWithRect","isContainedWithinRect","containsPoint"],"mappings":"kMAQaA,MAAAA,EACXC,KAESA,GAAgBC,MAAMC,QAASF,EAAuBG,UAG1D,SAASC,EAAiDC,GAC/D,MAAMC,UAAmBD,EAAKE,WAAAA,GAAAC,SAAAC,WAC5BC,kBAI2B,GAAE,CAG7BC,cAAAA,CAAeC,GACb,CAIFC,gBAAAA,CAAiBD,GACf,CAIFE,oBAAAA,CAAqBF,GACnB,CASFG,GAAAA,GAAwC,IAAA,IAAAC,EAAAP,UAAAQ,OAAjCC,EAAOjB,IAAAA,MAAAe,GAAAG,EAAA,EAAAA,EAAAH,EAAAG,IAAPD,EAAOC,GAAAV,UAAAU,GACZ,MAAMC,EAAOC,KAAKlB,SAASmB,QAAQJ,GAEnC,OADAA,EAAQK,SAASX,GAAWS,KAAKV,eAAeC,KACzCQ,CACT,CAQAI,QAAAA,CAASC,GAA2C,IAAAC,IAAAA,EAAAjB,UAAAQ,OAAzBC,MAAOjB,MAAAyB,EAAAA,EAAAA,OAAAC,EAAA,EAAAA,EAAAD,EAAAC,IAAPT,EAAOS,EAAAlB,GAAAA,UAAAkB,GAGhC,OAFAN,KAAKlB,SAASyB,OAAOH,EAAO,KAAMP,GAClCA,EAAQK,SAASX,GAAWS,KAAKV,eAAeC,KACzCS,KAAKlB,SAASc,MACvB,CAQAY,MAAAA,GACE,MAAMC,EAAQT,KAAKlB,SACjB4B,EAA0B,GAAG,IAAA,IAAAC,EAAAvB,UAAAQ,OAFvBC,EAAOjB,IAAAA,MAAA+B,GAAAC,EAAA,EAAAA,EAAAD,EAAAC,IAAPf,EAAOe,GAAAxB,UAAAwB,GAYf,OATAf,EAAQK,SAASX,IACf,MAAMa,EAAQK,EAAMI,QAAQtB,IAEb,IAAXa,IACFK,EAAMF,OAAOH,EAAO,GACpBM,EAAQT,KAAKV,GACbS,KAAKR,iBAAiBD,GACxB,IAEKmB,CACT,CAUAI,aAAAA,CACEC,GAMAf,KAAKgB,aAAad,SAAQ,CAACX,EAAQa,EAAOP,IACxCkB,EAASxB,EAAQa,EAAOP,IAE5B,CAOAmB,UAAAA,GAA+B,IAAA,IAAAC,EAAA7B,UAAAQ,OAAjBsB,EAAKtC,IAAAA,MAAAqC,GAAAE,EAAA,EAAAA,EAAAF,EAAAE,IAALD,EAAKC,GAAA/B,UAAA+B,GACjB,OAAqB,IAAjBD,EAAMtB,OACD,IAAII,KAAKlB,UAEXkB,KAAKlB,SAASsC,QAAQC,GAAMA,EAAEC,UAAUJ,IACjD,CAOAK,IAAAA,CAAKnB,GACH,OAAOJ,KAAKlB,SAASsB,EACvB,CAMAoB,OAAAA,GACE,OAAgC,IAAzBxB,KAAKlB,SAASc,MACvB,CAMAG,IAAAA,GACE,OAAOC,KAAKlB,SAASc,MACvB,CAUA6B,QAAAA,CAASlC,EAAsBmC,GAC7B,QAAI1B,KAAKlB,SAAS6C,SAASpC,MAEhBmC,GACF1B,KAAKlB,SAAS8C,MAClBC,GACCA,aAAe5C,GACd4C,EAA8BJ,SAASlC,GAAQ,IAIxD,CAMAuC,UAAAA,GACE,OAAO9B,KAAKlB,SAASiD,QAAO,CAACC,EAAMC,IACjCD,GAAQC,EAAQH,WAAaG,EAAQH,aAAe,GAEnD,EACL,CAQAI,gBAAAA,CAAiB3C,GACf,SAAKA,GAAUA,IAAWS,KAAKlB,SAAS,MAGxCqD,EAAgBnC,KAAKlB,SAAUS,GAC/BS,KAAKlB,SAASsD,QAAQ7C,GACtBS,KAAKP,qBAAqBF,IACnB,EACT,CAQA8C,kBAAAA,CAAmB9C,GACjB,SAAKA,GAAUA,IAAWS,KAAKlB,SAASkB,KAAKlB,SAASc,OAAS,MAG/DuC,EAAgBnC,KAAKlB,SAAUS,GAC/BS,KAAKlB,SAASmB,KAAKV,GACnBS,KAAKP,qBAAqBF,IACnB,EACT,CAYA+C,mBAAAA,CAAoB/C,EAAsBgD,GACxC,IAAKhD,EACH,OAAO,EAET,MAAMiD,EAAMxC,KAAKlB,SAAS+B,QAAQtB,GAClC,GAAY,IAARiD,EAAW,CAEb,MAAMC,EAASzC,KAAK0C,kBAAkBnD,EAAQiD,EAAKD,GAInD,OAHAJ,EAAgBnC,KAAKlB,SAAUS,GAC/BS,KAAKlB,SAASyB,OAAOkC,EAAQ,EAAGlD,GAChCS,KAAKP,qBAAqBF,IACnB,CACT,CACA,OAAO,CACT,CAYAoD,kBAAAA,CAAmBpD,EAAsBgD,GACvC,IAAKhD,EACH,OAAO,EAET,MAAMiD,EAAMxC,KAAKlB,SAAS+B,QAAQtB,GAClC,GAAIiD,IAAQxC,KAAKlB,SAASc,OAAS,EAAG,CAEpC,MAAM6C,EAASzC,KAAK4C,kBAAkBrD,EAAQiD,EAAKD,GAInD,OAHAJ,EAAgBnC,KAAKlB,SAAUS,GAC/BS,KAAKlB,SAASyB,OAAOkC,EAAQ,EAAGlD,GAChCS,KAAKP,qBAAqBF,IACnB,CACT,CACA,OAAO,CACT,CAQAsD,YAAAA,CAAatD,EAAsBa,GACjC,OAAIb,IAAWS,KAAKlB,SAASsB,KAG7B+B,EAAgBnC,KAAKlB,SAAUS,GAC/BS,KAAKlB,SAASyB,OAAOH,EAAO,EAAGb,GAC/BS,KAAKP,qBAAqBF,IACnB,EACT,CAEAmD,iBAAAA,CACEnD,EACAiD,EACAD,GAEA,IAAIE,EAEJ,GAAIF,EAAc,CAChBE,EAASD,EAET,IAAK,IAAIM,EAAIN,EAAM,EAAGM,GAAK,IAAKA,EAC9B,GAAIvD,EAAOwD,cAAc/C,KAAKlB,SAASgE,IAAK,CAC1CL,EAASK,EACT,KACF,CAEJ,MACEL,EAASD,EAAM,EAGjB,OAAOC,CACT,CAEAG,iBAAAA,CACErD,EACAiD,EACAD,GAEA,IAAIE,EAEJ,GAAIF,EAAc,CAChBE,EAASD,EAET,IAAK,IAAIM,EAAIN,EAAM,EAAGM,EAAI9C,KAAKlB,SAASc,SAAUkD,EAChD,GAAIvD,EAAOwD,cAAc/C,KAAKlB,SAASgE,IAAK,CAC1CL,EAASK,EACT,KACF,CAEJ,MACEL,EAASD,EAAM,EAGjB,OAAOC,CACT,CAUAO,cAAAA,CAAcC,GAGZ,IAFAC,KAAEA,EAAIC,IAAEA,EAAGC,MAAEA,EAAKC,OAAEA,GAAeJ,GACnCK,oBAAEA,GAAsB,GAAyClE,UAAAQ,OAAAR,QAAAmE,IAAAnE,UAAAmE,GAAAnE,UAAG,GAAA,GAEpE,MAAMS,EAAqC,GACzC2D,EAAK,IAAIC,EAAMP,EAAMC,GACrBO,EAAKF,EAAG9D,IAAI,IAAI+D,EAAML,EAAOC,IAG/B,IAAK,IAAIP,EAAI9C,KAAKlB,SAASc,OAAS,EAAGkD,GAAK,EAAGA,IAAK,CAClD,MAAMvD,EAASS,KAAKlB,SAASgE,GAE3BvD,EAAOoE,YACPpE,EAAOqE,UACLN,GAAuB/D,EAAOsE,mBAAmBL,EAAIE,IACrDnE,EAAOuE,sBAAsBN,EAAIE,IAChCJ,GAAuB/D,EAAOwE,cAAcP,IAC5CF,GAAuB/D,EAAOwE,cAAcL,KAE/C7D,EAAQI,KAAKV,EAEjB,CAEA,OAAOM,CACT,EAIF,OAAOZ,CACT"}