{"version":3,"file":"FabricObjectSVGExportMixin.min.mjs","names":[],"sources":["../../../../src/shapes/Object/FabricObjectSVGExportMixin.ts"],"sourcesContent":["import type { TSVGReviver } from '../../typedefs';\nimport {\n  getSafeSvgStyleNumber,\n  getSafeSvgStyleToken,\n} from '../../util/internals/svgExportCheck';\nimport { uid } from '../../util/internals/uid';\nimport { colorPropToSVG } from '../../util/misc/svgParsing';\nimport { FILL, NONE, STROKE } from '../../constants';\nimport type { FabricObject } from './FabricObject';\nimport { isFiller } from '../../util/typeAssertions';\nimport { matrixToSVG } from '../../util/misc/svgExport';\nimport { escapeXml } from '../../util/lang_string';\n\nexport class FabricObjectSVGExportMixin {\n  /**\n   * When an object is being exported as SVG as a clippath, a reference inside the SVG is needed.\n   * This reference is a UID in the fabric namespace and is temporary stored here.\n   * @type {String}\n   */\n  declare clipPathId?: string;\n\n  /**\n   * Returns styles-string for svg-export\n   * @param {Boolean} skipShadow a boolean to skip shadow filter output\n   * @return {String}\n   */\n  getSvgStyles(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    skipShadow?: boolean,\n  ) {\n    const fillRule =\n        this.fillRule == null ? 'nonzero' : getSafeSvgStyleToken(this.fillRule),\n      strokeWidth =\n        this.strokeWidth == null\n          ? '0'\n          : getSafeSvgStyleNumber(this.strokeWidth),\n      strokeDashArray =\n        this.strokeDashArray == null\n          ? NONE\n          : this.strokeDashArray.every((value) =>\n                Number.isFinite(Number(value)),\n              )\n            ? this.strokeDashArray.join(' ')\n            : '',\n      strokeDashOffset =\n        this.strokeDashOffset == null\n          ? '0'\n          : getSafeSvgStyleNumber(this.strokeDashOffset),\n      strokeLineCap =\n        this.strokeLineCap == null\n          ? 'butt'\n          : getSafeSvgStyleToken(this.strokeLineCap),\n      strokeLineJoin =\n        this.strokeLineJoin == null\n          ? 'miter'\n          : getSafeSvgStyleToken(this.strokeLineJoin),\n      strokeMiterLimit =\n        this.strokeMiterLimit == null\n          ? '4'\n          : getSafeSvgStyleNumber(this.strokeMiterLimit),\n      opacity =\n        this.opacity == null ? '1' : getSafeSvgStyleNumber(this.opacity),\n      visibility = this.visible ? '' : ' visibility: hidden;',\n      filter = skipShadow ? '' : this.getSvgFilter(),\n      fill = colorPropToSVG(FILL, this.fill),\n      stroke = colorPropToSVG(STROKE, this.stroke);\n\n    return [\n      stroke,\n      strokeWidth ? `stroke-width: ${strokeWidth}; ` : '',\n      strokeDashArray ? `stroke-dasharray: ${strokeDashArray}; ` : '',\n      strokeLineCap ? `stroke-linecap: ${strokeLineCap}; ` : '',\n      strokeDashOffset ? `stroke-dashoffset: ${strokeDashOffset}; ` : '',\n      strokeLineJoin ? `stroke-linejoin: ${strokeLineJoin}; ` : '',\n      strokeMiterLimit ? `stroke-miterlimit: ${strokeMiterLimit}; ` : '',\n      fill,\n      fillRule ? `fill-rule: ${fillRule}; ` : '',\n      opacity ? `opacity: ${opacity};` : '',\n      filter,\n      visibility,\n    ]\n      .map((v) => escapeXml(v))\n      .join('');\n  }\n\n  /**\n   * Returns filter for svg shadow\n   * @return {String}\n   */\n  getSvgFilter(this: FabricObjectSVGExportMixin & FabricObject) {\n    return this.shadow\n      ? `filter: url(#SVGID_${escapeXml(this.shadow.id)});`\n      : '';\n  }\n\n  /**\n   * Returns id attribute for svg output\n   * @return {String}\n   */\n  getSvgCommons(\n    this: FabricObjectSVGExportMixin & FabricObject & { id?: string },\n  ) {\n    return [\n      this.id ? `id=\"${escapeXml(String(this.id))}\" ` : '',\n      this.clipPath\n        ? `clip-path=\"url(#${escapeXml(\n            (this.clipPath as FabricObjectSVGExportMixin & FabricObject)\n              .clipPathId!,\n          )})\" `\n        : '',\n    ].join('');\n  }\n\n  /**\n   * Returns transform-string for svg-export\n   * @param {Boolean} use the full transform or the single object one.\n   * @return {String}\n   */\n  getSvgTransform(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    full?: boolean,\n    additionalTransform = '',\n  ) {\n    const transform = full ? this.calcTransformMatrix() : this.calcOwnMatrix(),\n      svgTransform = `transform=\"${matrixToSVG(transform)}`;\n    return `${svgTransform}${additionalTransform}\" `;\n  }\n\n  /**\n   * Returns svg representation of an instance\n   * This function is implemented in each subclass\n   * This is just because typescript otherwise cryies all the time\n   * @return {Array} an array of strings with the specific svg representation\n   * of the instance\n   */\n  _toSVG(_reviver?: TSVGReviver): string[] {\n    return [''];\n  }\n\n  /**\n   * Returns svg representation of an instance\n   * @param {TSVGReviver} [reviver] Method for further parsing of svg representation.\n   * @return {String} svg representation of an instance\n   */\n  toSVG(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    reviver?: TSVGReviver,\n  ) {\n    return this._createBaseSVGMarkup(this._toSVG(reviver), {\n      reviver,\n    });\n  }\n\n  /**\n   * Returns svg clipPath representation of an instance\n   * @param {TSVGReviver} [reviver] Method for further parsing of svg representation.\n   * @return {String} svg representation of an instance\n   */\n  toClipPathSVG(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    reviver?: TSVGReviver,\n  ) {\n    return (\n      '\\t' +\n      this._createBaseClipPathSVGMarkup(this._toSVG(reviver), {\n        reviver,\n      })\n    );\n  }\n\n  /**\n   * @private\n   */\n  _createBaseClipPathSVGMarkup(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    objectMarkup: string[],\n    {\n      reviver,\n      additionalTransform = '',\n    }: { reviver?: TSVGReviver; additionalTransform?: string } = {},\n  ) {\n    const commonPieces = [\n        this.getSvgTransform(true, additionalTransform),\n        this.getSvgCommons(),\n      ].join(''),\n      // insert commons in the markup, style and svgCommons\n      index = objectMarkup.indexOf('COMMON_PARTS');\n    objectMarkup[index] = commonPieces;\n    return reviver ? reviver(objectMarkup.join('')) : objectMarkup.join('');\n  }\n\n  /**\n   * @private\n   */\n  _createBaseSVGMarkup(\n    this: FabricObjectSVGExportMixin & FabricObject,\n    objectMarkup: string[],\n    {\n      noStyle,\n      reviver,\n      withShadow,\n      additionalTransform,\n    }: {\n      noStyle?: boolean;\n      reviver?: TSVGReviver;\n      withShadow?: boolean;\n      additionalTransform?: string;\n    } = {},\n  ): string {\n    const styleInfo = noStyle ? '' : `style=\"${this.getSvgStyles()}\" `,\n      shadowInfo = withShadow ? `style=\"${this.getSvgFilter()}\" ` : '',\n      clipPath = this.clipPath as FabricObjectSVGExportMixin & FabricObject,\n      vectorEffect = this.strokeUniform\n        ? 'vector-effect=\"non-scaling-stroke\" '\n        : '',\n      absoluteClipPath = clipPath && clipPath.absolutePositioned,\n      stroke = this.stroke,\n      fill = this.fill,\n      shadow = this.shadow,\n      markup = [],\n      // insert commons in the markup, style and svgCommons\n      index = objectMarkup.indexOf('COMMON_PARTS');\n    let clipPathMarkup;\n    if (clipPath) {\n      clipPath.clipPathId = `CLIPPATH_${uid()}`;\n      clipPathMarkup = `<clipPath id=\"${\n        clipPath.clipPathId\n      }\" >\\n${clipPath.toClipPathSVG(reviver)}</clipPath>\\n`;\n    }\n    if (absoluteClipPath) {\n      markup.push('<g ', shadowInfo, this.getSvgCommons(), ' >\\n');\n    }\n    markup.push(\n      '<g ',\n      this.getSvgTransform(false),\n      !absoluteClipPath ? shadowInfo + this.getSvgCommons() : '',\n      ' >\\n',\n    );\n    const commonPieces = [\n      styleInfo,\n      vectorEffect,\n      noStyle ? '' : this.addPaintOrder(),\n      ' ',\n      additionalTransform ? `transform=\"${additionalTransform}\" ` : '',\n    ].join('');\n    objectMarkup[index] = commonPieces;\n    if (isFiller(fill)) {\n      markup.push(fill.toSVG(this));\n    }\n    if (isFiller(stroke)) {\n      markup.push(stroke.toSVG(this));\n    }\n    if (shadow) {\n      markup.push(shadow.toSVG(this));\n    }\n    if (clipPath) {\n      markup.push(clipPathMarkup);\n    }\n    markup.push(objectMarkup.join(''));\n    markup.push('</g>\\n');\n    absoluteClipPath && markup.push('</g>\\n');\n    return reviver ? reviver(markup.join('')) : markup.join('');\n  }\n\n  addPaintOrder(this: FabricObjectSVGExportMixin & FabricObject) {\n    return this.paintFirst !== FILL\n      ? ` paint-order=\"${escapeXml(this.paintFirst)}\" `\n      : '';\n  }\n}\n"],"mappings":"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"}