{"version":3,"file":"Shadow.mjs","names":[],"sources":["../../src/Shadow.ts"],"sourcesContent":["import { classRegistry } from './ClassRegistry';\nimport { Color } from './color/Color';\nimport { config } from './config';\nimport { reNum } from './parser/constants';\nimport { Point } from './Point';\nimport type { FabricObject } from './shapes/Object/FabricObject';\nimport type { TClassProperties } from './typedefs';\nimport { uid } from './util/internals/uid';\nimport { escapeXml } from './util/lang_string';\nimport { pickBy } from './util/misc/pick';\nimport { degreesToRadians } from './util/misc/radiansDegreesConversion';\nimport { toFixed } from './util/misc/toFixed';\nimport { rotateVector } from './util/misc/vectors';\n\n/**\n   * Regex matching shadow offsetX, offsetY and blur (ex: \"2px 2px 10px rgba(0,0,0,0.2)\", \"rgb(0,255,0) 2px 2px\")\n   * - (?:\\s|^): This part captures either a whitespace character (\\s) or the beginning of a line (^). It's non-capturing (due to (?:...)), meaning it doesn't create a capturing group.\n   * - (-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?: This captures the first component of the shadow, which is the horizontal offset. Breaking it down:\n   *   - (-?\\d+): Captures an optional minus sign followed by one or more digits (integer part of the number).\n   *   - (?:\\.\\d*)?: Optionally captures a decimal point followed by zero or more digits (decimal part of the number).\n   *   - (?:px)?: Optionally captures the \"px\" unit.\n   *   - (?:\\s?|$): Captures either an optional whitespace or the end of the line. This whole part is wrapped in a non-capturing group and marked as optional with ?.\n   * - (-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?: Similar to the previous step, this captures the vertical offset.\n\n(\\d+(?:\\.\\d*)?(?:px)?)?: This captures the blur radius. It's similar to the horizontal offset but without the optional minus sign.\n\n(?:\\s+(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?){0,1}: This captures an optional part for the color. It allows for whitespace followed by a component with an optional minus sign, digits, decimal point, and \"px\" unit.\n\n(?:$|\\s): This captures either the end of the line or a whitespace character. It ensures that the match ends either at the end of the string or with a whitespace character.\n   */\n\nconst shadowOffsetRegex = '(-?\\\\d+(?:\\\\.\\\\d*)?(?:px)?(?:\\\\s?|$))?';\n\nconst reOffsetsAndBlur = new RegExp(\n  '(?:\\\\s|^)' +\n    shadowOffsetRegex +\n    shadowOffsetRegex +\n    '(' +\n    reNum +\n    '?(?:px)?)?(?:\\\\s?|$)(?:$|\\\\s)',\n);\n\nexport const shadowDefaultValues: Partial<TClassProperties<Shadow>> = {\n  color: 'rgb(0,0,0)',\n  blur: 0,\n  offsetX: 0,\n  offsetY: 0,\n  affectStroke: false,\n  includeDefaultValues: true,\n  nonScaling: false,\n};\n\nexport type SerializedShadowOptions = {\n  color: string;\n  blur: number;\n  offsetX: number;\n  offsetY: number;\n  affectStroke: boolean;\n  nonScaling: boolean;\n  type: string;\n};\n\nexport class Shadow {\n  /**\n   * Shadow color\n   * @type String\n   */\n  declare color: string;\n\n  /**\n   * Shadow blur\n   * @type Number\n   */\n  declare blur: number;\n\n  /**\n   * Shadow horizontal offset\n   * @type Number\n   */\n  declare offsetX: number;\n\n  /**\n   * Shadow vertical offset\n   * @type Number\n   */\n  declare offsetY: number;\n\n  /**\n   * Whether the shadow should affect stroke operations\n   * @type Boolean\n   */\n  declare affectStroke: boolean;\n\n  /**\n   * Indicates whether toObject should include default values\n   * @type Boolean\n   */\n  declare includeDefaultValues: boolean;\n\n  /**\n   * When `false`, the shadow will scale with the object.\n   * When `true`, the shadow's offsetX, offsetY, and blur will not be affected by the object's scale.\n   * default to false\n   * @type Boolean\n   */\n  declare nonScaling: boolean;\n\n  declare id: number | string;\n\n  static ownDefaults = shadowDefaultValues;\n\n  static type = 'shadow';\n\n  /**\n   * @see {@link http://fabric5.fabricjs.com/shadows|Shadow demo}\n   * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetY properties or string (e.g. \"rgba(0,0,0,0.2) 2px 2px 10px\")\n   */\n  constructor(options?: Partial<TClassProperties<Shadow>>);\n  constructor(svgAttribute: string);\n  constructor(arg0: string | Partial<TClassProperties<Shadow>> = {}) {\n    const options: Partial<TClassProperties<Shadow>> =\n      typeof arg0 === 'string' ? Shadow.parseShadow(arg0) : arg0;\n    Object.assign(this, Shadow.ownDefaults, options);\n    this.id = uid();\n  }\n\n  /**\n   * @param {String} value Shadow value to parse\n   * @return {Object} Shadow object with color, offsetX, offsetY and blur\n   */\n  static parseShadow(value: string) {\n    const shadowStr = value.trim(),\n      [, offsetX = 0, offsetY = 0, blur = 0] = (\n        reOffsetsAndBlur.exec(shadowStr) || []\n      ).map((value) => parseFloat(value) || 0),\n      color = (shadowStr.replace(reOffsetsAndBlur, '') || 'rgb(0,0,0)').trim();\n\n    return {\n      color,\n      offsetX,\n      offsetY,\n      blur,\n    };\n  }\n\n  /**\n   * Returns a string representation of an instance\n   * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow\n   * @return {String} Returns CSS3 text-shadow declaration\n   */\n  toString() {\n    return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');\n  }\n\n  /**\n   * Returns SVG representation of a shadow\n   * @param {FabricObject} object\n   * @return {String} SVG representation of a shadow\n   */\n  toSVG(object: FabricObject) {\n    const offset = rotateVector(\n        new Point(this.offsetX, this.offsetY),\n        degreesToRadians(-object.angle),\n      ),\n      BLUR_BOX = 20,\n      NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS,\n      color = new Color(this.color);\n    let fBoxX = 40,\n      fBoxY = 40;\n\n    if (object.width && object.height) {\n      //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion\n      // we add some extra space to filter box to contain the blur ( 20 )\n      fBoxX =\n        toFixed(\n          (Math.abs(offset.x) + this.blur) / object.width,\n          NUM_FRACTION_DIGITS,\n        ) *\n          100 +\n        BLUR_BOX;\n      fBoxY =\n        toFixed(\n          (Math.abs(offset.y) + this.blur) / object.height,\n          NUM_FRACTION_DIGITS,\n        ) *\n          100 +\n        BLUR_BOX;\n    }\n    if (object.flipX) {\n      offset.x *= -1;\n    }\n    if (object.flipY) {\n      offset.y *= -1;\n    }\n\n    return `<filter id=\"SVGID_${escapeXml(this.id)}\" y=\"-${fBoxY}%\" height=\"${\n      100 + 2 * fBoxY\n    }%\" x=\"-${fBoxX}%\" width=\"${\n      100 + 2 * fBoxX\n    }%\" >\\n\\t<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"${toFixed(\n      this.blur ? this.blur / 2 : 0,\n      NUM_FRACTION_DIGITS,\n    )}\"></feGaussianBlur>\\n\\t<feOffset dx=\"${toFixed(\n      offset.x,\n      NUM_FRACTION_DIGITS,\n    )}\" dy=\"${toFixed(\n      offset.y,\n      NUM_FRACTION_DIGITS,\n    )}\" result=\"oBlur\" ></feOffset>\\n\\t<feFlood flood-color=\"${color.toRgb()}\" flood-opacity=\"${color.getAlpha()}\"/>\\n\\t<feComposite in2=\"oBlur\" operator=\"in\" />\\n\\t<feMerge>\\n\\t\\t<feMergeNode></feMergeNode>\\n\\t\\t<feMergeNode in=\"SourceGraphic\"></feMergeNode>\\n\\t</feMerge>\\n</filter>\\n`;\n  }\n\n  /**\n   * Returns object representation of a shadow\n   * @return {Object} Object representation of a shadow instance\n   */\n  toObject() {\n    const data: SerializedShadowOptions = {\n      color: this.color,\n      blur: this.blur,\n      offsetX: this.offsetX,\n      offsetY: this.offsetY,\n      affectStroke: this.affectStroke,\n      nonScaling: this.nonScaling,\n      type: (this.constructor as typeof Shadow).type,\n    };\n    const defaults = Shadow.ownDefaults as SerializedShadowOptions;\n    return !this.includeDefaultValues\n      ? pickBy(data, (value, key) => value !== defaults[key])\n      : data;\n  }\n\n  static async fromObject(options: Partial<TClassProperties<Shadow>>) {\n    return new this(options);\n  }\n}\n\nclassRegistry.setClass(Shadow, 'shadow');\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,oBAAoB;AAE1B,MAAM,mBAAmB,IAAI,OAC3B,cACE,oBACA,oBACA,MACA,QACA,gCACH;AAED,MAAa,sBAAyD;CACpE,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACT,cAAc;CACd,sBAAsB;CACtB,YAAY;CACb;AAYD,IAAa,SAAb,MAAa,OAAO;CAyDlB,YAAY,OAAmD,EAAE,EAAE;EACjE,MAAM,UACJ,OAAO,SAAS,WAAW,OAAO,YAAY,KAAK,GAAG;AACxD,SAAO,OAAO,MAAM,OAAO,aAAa,QAAQ;AAChD,OAAK,KAAK,KAAK;;;;;;CAOjB,OAAO,YAAY,OAAe;EAChC,MAAM,YAAY,MAAM,MAAM,EAC5B,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,MAClC,iBAAiB,KAAK,UAAU,IAAI,EAAE,EACtC,KAAK,UAAU,WAAW,MAAM,IAAI,EAAE;AAG1C,SAAO;GACL,QAHS,UAAU,QAAQ,kBAAkB,GAAG,IAAI,cAAc,MAAM;GAIxE;GACA;GACA;GACD;;;;;;;CAQH,WAAW;AACT,SAAO;GAAC,KAAK;GAAS,KAAK;GAAS,KAAK;GAAM,KAAK;GAAM,CAAC,KAAK,MAAM;;;;;;;CAQxE,MAAM,QAAsB;EAC1B,MAAM,SAAS,aACX,IAAI,MAAM,KAAK,SAAS,KAAK,QAAQ,EACrC,iBAAiB,CAAC,OAAO,MAAM,CAChC,EACD,WAAW,IACX,sBAAsB,OAAO,qBAC7B,QAAQ,IAAI,MAAM,KAAK,MAAM;EAC/B,IAAI,QAAQ,IACV,QAAQ;AAEV,MAAI,OAAO,SAAS,OAAO,QAAQ;AAGjC,WACE,SACG,KAAK,IAAI,OAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,OAC1C,oBACD,GACC,MACF;AACF,WACE,SACG,KAAK,IAAI,OAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,QAC1C,oBACD,GACC,MACF;;AAEJ,MAAI,OAAO,MACT,QAAO,KAAK;AAEd,MAAI,OAAO,MACT,QAAO,KAAK;AAGd,SAAO,qBAAqB,UAAU,KAAK,GAAG,CAAC,QAAQ,MAAM,aAC3D,MAAM,IAAI,MACX,SAAS,MAAM,YACd,MAAM,IAAI,MACX,yDAAyD,QACxD,KAAK,OAAO,KAAK,OAAO,IAAI,GAC5B,oBACD,CAAC,uCAAuC,QACvC,OAAO,GACP,oBACD,CAAC,QAAQ,QACR,OAAO,GACP,oBACD,CAAC,yDAAyD,MAAM,OAAO,CAAC,mBAAmB,MAAM,UAAU,CAAC;;;;;;CAO/G,WAAW;EACT,MAAM,OAAgC;GACpC,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,SAAS,KAAK;GACd,SAAS,KAAK;GACd,cAAc,KAAK;GACnB,YAAY,KAAK;GACjB,MAAO,KAAK,YAA8B;GAC3C;EACD,MAAM,WAAW,OAAO;AACxB,SAAO,CAAC,KAAK,uBACT,OAAO,OAAO,OAAO,QAAQ,UAAU,SAAS,KAAK,GACrD;;CAGN,aAAa,WAAW,SAA4C;AAClE,SAAO,IAAI,KAAK,QAAQ;;;wBA3HnB,eAAc,oBAAoB;wBAElC,QAAO,SAAS;AA6HzB,cAAc,SAAS,QAAQ,SAAS"}