fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
1 lines • 10.6 kB
Source Map (JSON)
{"version":3,"file":"FabricObjectSVGExportMixin.min.mjs","names":[],"sources":["../../../../src/shapes/Object/FabricObjectSVGExportMixin.ts"],"sourcesContent":["import type { TSVGReviver } from '../../typedefs';\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 = this.fillRule ? this.fillRule : 'nonzero',\n strokeWidth = this.strokeWidth ? this.strokeWidth : '0',\n strokeDashArray = this.strokeDashArray\n ? this.strokeDashArray.join(' ')\n : NONE,\n strokeDashOffset = this.strokeDashOffset ? this.strokeDashOffset : '0',\n strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',\n strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',\n strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',\n opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',\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 'stroke-width: ',\n strokeWidth,\n '; ',\n 'stroke-dasharray: ',\n strokeDashArray,\n '; ',\n 'stroke-linecap: ',\n strokeLineCap,\n '; ',\n 'stroke-dashoffset: ',\n strokeDashOffset,\n '; ',\n 'stroke-linejoin: ',\n strokeLineJoin,\n '; ',\n 'stroke-miterlimit: ',\n strokeMiterLimit,\n '; ',\n fill,\n 'fill-rule: ',\n fillRule,\n '; ',\n 'opacity: ',\n opacity,\n ';',\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(#${\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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"}