{"version":3,"file":"Pattern.min.mjs","sources":["../../../src/Pattern/Pattern.ts"],"sourcesContent":["import { config } from '../config';\nimport type { Abortable, TCrossOrigin, TMat2D, TSize } from '../typedefs';\nimport { ifNaN } from '../util/internals/ifNaN';\nimport { uid } from '../util/internals/uid';\nimport { loadImage } from '../util/misc/objectEnlive';\nimport { pick } from '../util/misc/pick';\nimport { toFixed } from '../util/misc/toFixed';\nimport { classRegistry } from '../ClassRegistry';\nimport type {\n  PatternRepeat,\n  PatternOptions,\n  SerializedPatternOptions,\n} from './types';\nimport { log } from '../util/internals/console';\nimport { escapeXml } from '../util/lang_string';\n\n/**\n * @see {@link http://fabric5.fabricjs.com/patterns demo}\n * @see {@link http://fabric5.fabricjs.com/dynamic-patterns demo}\n */\nexport class Pattern {\n  static type = 'Pattern';\n\n  /**\n   * Legacy identifier of the class. Prefer using this.constructor.type 'Pattern'\n   * or utils like isPattern, or instance of to indentify a pattern in your code.\n   * Will be removed in future versiones\n   * @TODO add sustainable warning message\n   * @type string\n   * @deprecated\n   */\n  get type() {\n    return 'pattern';\n  }\n\n  set type(value) {\n    log('warn', 'Setting type has no effect', value);\n  }\n\n  /**\n   * @type PatternRepeat\n   * @defaults\n   */\n  repeat: PatternRepeat = 'repeat';\n\n  /**\n   * Pattern horizontal offset from object's left/top corner\n   * @type Number\n   */\n  offsetX = 0;\n\n  /**\n   * Pattern vertical offset from object's left/top corner\n   * @type Number\n   */\n  offsetY = 0;\n\n  /**\n   * @type TCrossOrigin\n   */\n  crossOrigin: TCrossOrigin = '';\n\n  /**\n   * transform matrix to change the pattern, imported from svgs.\n   * @todo verify if using the identity matrix as default makes the rest of the code more easy\n   * @type Array\n   */\n  declare patternTransform?: TMat2D;\n\n  /**\n   * The actual pixel source of the pattern\n   */\n  declare source: CanvasImageSource;\n\n  /**\n   * If true, this object will not be exported during the serialization of a canvas\n   * @type boolean\n   */\n  declare excludeFromExport?: boolean;\n\n  /**\n   * ID used for SVG export functionalities\n   * @type number\n   */\n  declare readonly id: number;\n\n  /**\n   * Constructor\n   * @param {Object} [options] Options object\n   * @param {option.source} [source] the pattern source, eventually empty or a drawable\n   */\n  constructor(options: PatternOptions) {\n    this.id = uid();\n    Object.assign(this, options);\n  }\n\n  /**\n   * @returns true if {@link source} is an <img> element\n   */\n  isImageSource(): this is { source: HTMLImageElement } {\n    return (\n      !!this.source && typeof (this.source as HTMLImageElement).src === 'string'\n    );\n  }\n\n  /**\n   * @returns true if {@link source} is a <canvas> element\n   */\n  isCanvasSource(): this is { source: HTMLCanvasElement } {\n    return !!this.source && !!(this.source as HTMLCanvasElement).toDataURL;\n  }\n\n  sourceToString(): string {\n    return this.isImageSource()\n      ? this.source.src\n      : this.isCanvasSource()\n        ? this.source.toDataURL()\n        : '';\n  }\n\n  /**\n   * Returns an instance of CanvasPattern\n   * @param {CanvasRenderingContext2D} ctx Context to create pattern\n   * @return {CanvasPattern}\n   */\n  toLive(ctx: CanvasRenderingContext2D): CanvasPattern | null {\n    if (\n      // if the image failed to load, return, and allow rest to continue loading\n      !this.source ||\n      // if an image\n      (this.isImageSource() &&\n        (!this.source.complete ||\n          this.source.naturalWidth === 0 ||\n          this.source.naturalHeight === 0))\n    ) {\n      return null;\n    }\n\n    return ctx.createPattern(this.source, this.repeat)!;\n  }\n\n  /**\n   * Returns object representation of a pattern\n   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n   * @return {object} Object representation of a pattern instance\n   */\n  toObject(propertiesToInclude: string[] = []): Record<string, any> {\n    const { repeat, crossOrigin } = this;\n    return {\n      ...pick(this, propertiesToInclude as (keyof this)[]),\n      type: 'pattern',\n      source: this.sourceToString(),\n      repeat,\n      crossOrigin,\n      offsetX: toFixed(this.offsetX, config.NUM_FRACTION_DIGITS),\n      offsetY: toFixed(this.offsetY, config.NUM_FRACTION_DIGITS),\n      patternTransform: this.patternTransform\n        ? [...this.patternTransform]\n        : null,\n    };\n  }\n\n  /* _TO_SVG_START_ */\n  /**\n   * Returns SVG representation of a pattern\n   */\n  toSVG({ width, height }: TSize): string {\n    const { source: patternSource, repeat, id } = this,\n      patternOffsetX = ifNaN(this.offsetX / width, 0),\n      patternOffsetY = ifNaN(this.offsetY / height, 0),\n      patternWidth =\n        repeat === 'repeat-y' || repeat === 'no-repeat'\n          ? 1 + Math.abs(patternOffsetX || 0)\n          : ifNaN((patternSource as HTMLImageElement).width / width, 0),\n      patternHeight =\n        repeat === 'repeat-x' || repeat === 'no-repeat'\n          ? 1 + Math.abs(patternOffsetY || 0)\n          : ifNaN((patternSource as HTMLImageElement).height / height, 0);\n\n    return [\n      `<pattern id=\"SVGID_${escapeXml(id)}\" x=\"${patternOffsetX}\" y=\"${patternOffsetY}\" width=\"${patternWidth}\" height=\"${patternHeight}\">`,\n      `<image x=\"0\" y=\"0\" width=\"${\n        (patternSource as HTMLImageElement).width\n      }\" height=\"${\n        (patternSource as HTMLImageElement).height\n      }\" xlink:href=\"${escapeXml(this.sourceToString())}\"></image>`,\n      `</pattern>`,\n      '',\n    ].join('\\n');\n  }\n  /* _TO_SVG_END_ */\n\n  static async fromObject(\n    {\n      type,\n      source,\n      patternTransform,\n      ...otherOptions\n    }: SerializedPatternOptions,\n    options?: Abortable,\n  ): Promise<Pattern> {\n    const img = await loadImage(source, {\n      ...options,\n      crossOrigin: otherOptions.crossOrigin,\n    });\n    return new this({\n      ...otherOptions,\n      patternTransform:\n        patternTransform && (patternTransform.slice(0) as TMat2D),\n      source: img,\n    });\n  }\n}\n\nclassRegistry.setClass(Pattern);\n// kept for compatibility reason\nclassRegistry.setClass(Pattern, 'pattern');\n"],"names":["Pattern","type","value","log","constructor","options","_defineProperty","this","id","uid","Object","assign","isImageSource","source","src","isCanvasSource","toDataURL","sourceToString","toLive","ctx","complete","naturalWidth","naturalHeight","createPattern","repeat","toObject","propertiesToInclude","arguments","length","undefined","crossOrigin","pick","offsetX","toFixed","config","NUM_FRACTION_DIGITS","offsetY","patternTransform","toSVG","_ref","width","height","patternSource","patternOffsetX","ifNaN","patternOffsetY","patternWidth","Math","abs","patternHeight","escapeXml","join","fromObject","_ref2","otherOptions","img","loadImage","slice","classRegistry","setClass"],"mappings":"wjBAoBO,MAAMA,EAWX,QAAIC,GACF,MAAO,SACT,CAEA,QAAIA,CAAKC,GACPC,EAAI,OAAQ,6BAA8BD,EAC5C,CAsDAE,WAAAA,CAAYC,GAAyBC,gBAhDb,UAExBA,iBAIU,GAEVA,iBAIU,GAEVA,qBAG4B,IAgC1BC,KAAKC,GAAKC,IACVC,OAAOC,OAAOJ,KAAMF,EACtB,CAKAO,aAAAA,GACE,QACIL,KAAKM,QAA2D,iBAAzCN,KAAKM,OAA4BC,GAE9D,CAKAC,cAAAA,GACE,QAASR,KAAKM,UAAaN,KAAKM,OAA6BG,SAC/D,CAEAC,cAAAA,GACE,OAAOV,KAAKK,gBACRL,KAAKM,OAAOC,IACZP,KAAKQ,iBACHR,KAAKM,OAAOG,YACZ,EACR,CAOAE,MAAAA,CAAOC,GACL,OAEGZ,KAAKM,UAELN,KAAKK,iBACFL,KAAKM,OAAOO,UACiB,IAA7Bb,KAAKM,OAAOQ,cACkB,IAA9Bd,KAAKM,OAAOS,eAKXH,EAAII,cAAchB,KAAKM,OAAQN,KAAKiB,QAHlC,IAIX,CAOAC,QAAAA,GAAkE,IAAzDC,EAA6BC,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAG,GACvC,MAAMH,OAAEA,EAAMM,YAAEA,GAAgBvB,KAChC,MAAO,IACFwB,EAAKxB,KAAMmB,GACdzB,KAAM,UACNY,OAAQN,KAAKU,iBACbO,SACAM,cACAE,QAASC,EAAQ1B,KAAKyB,QAASE,EAAOC,qBACtCC,QAASH,EAAQ1B,KAAK6B,QAASF,EAAOC,qBACtCE,iBAAkB9B,KAAK8B,iBACnB,IAAI9B,KAAK8B,kBACT,KAER,CAMAC,KAAAA,CAAKC,GAAmC,IAAlCC,MAAEA,EAAKC,OAAEA,GAAeF,EAC5B,MAAQ1B,OAAQ6B,EAAalB,OAAEA,EAAMhB,GAAEA,GAAOD,KAC5CoC,EAAiBC,EAAMrC,KAAKyB,QAAUQ,EAAO,GAC7CK,EAAiBD,EAAMrC,KAAK6B,QAAUK,EAAQ,GAC9CK,EACa,aAAXtB,GAAoC,cAAXA,EACrB,EAAIuB,KAAKC,IAAIL,GAAkB,GAC/BC,EAAOF,EAAmCF,MAAQA,EAAO,GAC/DS,EACa,aAAXzB,GAAoC,cAAXA,EACrB,EAAIuB,KAAKC,IAAIH,GAAkB,GAC/BD,EAAOF,EAAmCD,OAASA,EAAQ,GAEnE,MAAO,CACL,sBAAsBS,EAAU1C,UAAWmC,SAAsBE,aAA0BC,cAAyBG,MACpH,6BACGP,EAAmCF,kBAEnCE,EAAmCD,uBACrBS,EAAU3C,KAAKU,8BAChC,aACA,IACAkC,KAAK,KACT,CAGA,uBAAaC,CAAUC,EAOrBhD,GACkB,IAPlBJ,KACEA,EAAIY,OACJA,EAAMwB,iBACNA,KACGiB,GACsBD,EAG3B,MAAME,QAAYC,EAAU3C,EAAQ,IAC/BR,EACHyB,YAAawB,EAAaxB,cAE5B,OAAO,IAAIvB,KAAK,IACX+C,EACHjB,iBACEA,GAAqBA,EAAiBoB,MAAM,GAC9C5C,OAAQ0C,GAEZ,EACDjD,EAhMYN,EAAO,OACJ,WAiMhB0D,EAAcC,SAAS3D,GAEvB0D,EAAcC,SAAS3D,EAAS"}