fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
1 lines • 18.6 kB
Source Map (JSON)
{"version":3,"file":"TextSVGExportMixin.min.mjs","sources":["../../../../src/shapes/Text/TextSVGExportMixin.ts"],"sourcesContent":["import { config } from '../../config';\nimport type { TSVGReviver } from '../../typedefs';\nimport { escapeXml } from '../../util/lang_string';\nimport { colorPropToSVG, createSVGRect } from '../../util/misc/svgParsing';\nimport { hasStyleChanged } from '../../util/misc/textStyles';\nimport { toFixed } from '../../util/misc/toFixed';\nimport { FabricObjectSVGExportMixin } from '../Object/FabricObjectSVGExportMixin';\nimport { type TextStyleDeclaration } from './StyledText';\nimport { JUSTIFY } from '../Text/constants';\nimport type { FabricText, GraphemeBBox } from './Text';\nimport { STROKE, FILL } from '../../constants';\nimport { createRotateMatrix } from '../../util/misc/matrix';\nimport { radiansToDegrees } from '../../util/misc/radiansDegreesConversion';\nimport { Point } from '../../Point';\nimport { matrixToSVG } from '../../util/misc/svgExport';\n\nconst multipleSpacesRegex = / +/g;\nconst dblQuoteRegex = /\"/g;\n\nfunction createSVGInlineRect(\n color: string,\n left: number,\n top: number,\n width: number,\n height: number,\n) {\n return `\\t\\t${createSVGRect(color, { left, top, width, height })}\\n`;\n}\n\nexport class TextSVGExportMixin extends FabricObjectSVGExportMixin {\n _toSVG(this: TextSVGExportMixin & FabricText): string[] {\n const offsets = this._getSVGLeftTopOffsets(),\n textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);\n return this._wrapSVGTextAndBg(textAndBg);\n }\n\n toSVG(this: TextSVGExportMixin & FabricText, reviver?: TSVGReviver): string {\n const textSvg = this._createBaseSVGMarkup(this._toSVG(), {\n reviver,\n noStyle: true,\n withShadow: true,\n }),\n path = this.path;\n if (path) {\n return (\n textSvg +\n path._createBaseSVGMarkup(path._toSVG(), {\n reviver,\n withShadow: true,\n additionalTransform: matrixToSVG(this.calcOwnMatrix()),\n })\n );\n }\n return textSvg;\n }\n\n private _getSVGLeftTopOffsets(this: TextSVGExportMixin & FabricText) {\n return {\n textLeft: -this.width / 2,\n textTop: -this.height / 2,\n lineTop: this.getHeightOfLine(0),\n };\n }\n\n private _wrapSVGTextAndBg(\n this: TextSVGExportMixin & FabricText,\n {\n textBgRects,\n textSpans,\n }: {\n textSpans: string[];\n textBgRects: string[];\n },\n ) {\n const noShadow = true,\n textDecoration = this.getSvgTextDecoration(this);\n return [\n textBgRects.join(''),\n '\\t\\t<text xml:space=\"preserve\" ',\n `font-family=\"${escapeXml(this.fontFamily.replace(dblQuoteRegex, \"'\"))}\" `,\n `font-size=\"${escapeXml(this.fontSize)}\" `,\n this.fontStyle ? `font-style=\"${escapeXml(this.fontStyle)}\" ` : '',\n this.fontWeight ? `font-weight=\"${escapeXml(this.fontWeight)}\" ` : '',\n textDecoration ? `text-decoration=\"${textDecoration}\" ` : '',\n this.direction === 'rtl' ? `direction=\"rtl\" ` : '',\n 'style=\"',\n this.getSvgStyles(noShadow),\n '\"',\n this.addPaintOrder(),\n ' >',\n textSpans.join(''),\n '</text>\\n',\n ];\n }\n\n /**\n * @private\n * @param {Number} textTopOffset Text top offset\n * @param {Number} textLeftOffset Text left offset\n * @return {Object}\n */\n private _getSVGTextAndBg(\n this: TextSVGExportMixin & FabricText,\n textTopOffset: number,\n textLeftOffset: number,\n ) {\n const textSpans: string[] = [],\n textBgRects: string[] = [];\n let height = textTopOffset,\n lineOffset;\n\n // bounding-box background\n this.backgroundColor &&\n textBgRects.push(\n createSVGInlineRect(\n this.backgroundColor,\n -this.width / 2,\n -this.height / 2,\n this.width,\n this.height,\n ),\n );\n\n // text and text-background\n for (let i = 0, len = this._textLines.length; i < len; i++) {\n lineOffset = this._getLineLeftOffset(i);\n if (this.direction === 'rtl') {\n lineOffset += this.width;\n }\n if (this.textBackgroundColor || this.styleHas('textBackgroundColor', i)) {\n this._setSVGTextLineBg(\n textBgRects,\n i,\n textLeftOffset + lineOffset,\n height,\n );\n }\n this._setSVGTextLineText(\n textSpans,\n i,\n textLeftOffset + lineOffset,\n height,\n );\n height += this.getHeightOfLine(i);\n }\n\n return {\n textSpans,\n textBgRects,\n };\n }\n\n private _createTextCharSpan(\n this: TextSVGExportMixin & FabricText,\n char: string,\n styleDecl: TextStyleDeclaration,\n left: number,\n top: number,\n charBox: GraphemeBBox,\n ) {\n const numFractionDigit = config.NUM_FRACTION_DIGITS;\n const styleProps = this.getSvgSpanStyles(\n styleDecl,\n char !== char.trim() || !!char.match(multipleSpacesRegex),\n ),\n fillStyles = styleProps ? `style=\"${styleProps}\"` : '',\n dy = styleDecl.deltaY,\n dySpan = dy ? ` dy=\"${toFixed(dy, numFractionDigit)}\" ` : '',\n { angle, renderLeft, renderTop, width } = charBox;\n let angleAttr = '';\n if (renderLeft !== undefined) {\n const wBy2 = width / 2;\n angle &&\n (angleAttr = ` rotate=\"${toFixed(radiansToDegrees(angle), numFractionDigit)}\"`);\n const m = createRotateMatrix({ angle: radiansToDegrees(angle!) });\n m[4] = renderLeft!;\n m[5] = renderTop!;\n const renderPoint = new Point(-wBy2, 0).transform(m);\n left = renderPoint.x;\n top = renderPoint.y;\n }\n\n return `<tspan x=\"${toFixed(left, numFractionDigit)}\" y=\"${toFixed(\n top,\n numFractionDigit,\n )}\" ${dySpan}${angleAttr}${fillStyles}>${escapeXml(char)}</tspan>`;\n }\n\n private _setSVGTextLineText(\n this: TextSVGExportMixin & FabricText,\n textSpans: string[],\n lineIndex: number,\n textLeftOffset: number,\n textTopOffset: number,\n ) {\n const lineHeight = this.getHeightOfLine(lineIndex),\n isJustify = this.textAlign.includes(JUSTIFY),\n line = this._textLines[lineIndex];\n let actualStyle,\n nextStyle,\n charsToRender = '',\n charBox,\n style,\n boxWidth = 0,\n timeToRender;\n\n textTopOffset +=\n (lineHeight * (1 - this._fontSizeFraction)) / this.lineHeight;\n for (let i = 0, len = line.length - 1; i <= len; i++) {\n timeToRender = i === len || this.charSpacing || this.path;\n charsToRender += line[i];\n charBox = this.__charBounds[lineIndex][i];\n if (boxWidth === 0) {\n textLeftOffset += charBox.kernedWidth - charBox.width;\n boxWidth += charBox.width;\n } else {\n boxWidth += charBox.kernedWidth;\n }\n if (isJustify && !timeToRender) {\n if (this._reSpaceAndTab.test(line[i])) {\n timeToRender = true;\n }\n }\n if (!timeToRender) {\n // if we have charSpacing or a path, we render char by char\n actualStyle =\n actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n timeToRender = hasStyleChanged(actualStyle, nextStyle, true);\n }\n if (timeToRender) {\n style = this._getStyleDeclaration(lineIndex, i);\n textSpans.push(\n this._createTextCharSpan(\n charsToRender,\n style,\n textLeftOffset,\n textTopOffset,\n charBox,\n ),\n );\n charsToRender = '';\n actualStyle = nextStyle;\n if (this.direction === 'rtl') {\n textLeftOffset -= boxWidth;\n } else {\n textLeftOffset += boxWidth;\n }\n boxWidth = 0;\n }\n }\n }\n\n private _setSVGTextLineBg(\n this: TextSVGExportMixin & FabricText,\n textBgRects: (string | number)[],\n i: number,\n leftOffset: number,\n textTopOffset: number,\n ) {\n const line = this._textLines[i],\n heightOfLine = this.getHeightOfLine(i) / this.lineHeight;\n let boxWidth = 0,\n boxStart = 0,\n currentColor,\n lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n for (let j = 0; j < line.length; j++) {\n const { left, width, kernedWidth } = this.__charBounds[i][j];\n currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n if (currentColor !== lastColor) {\n lastColor &&\n textBgRects.push(\n createSVGInlineRect(\n lastColor,\n leftOffset + boxStart,\n textTopOffset,\n boxWidth,\n heightOfLine,\n ),\n );\n boxStart = left;\n boxWidth = width;\n lastColor = currentColor;\n } else {\n boxWidth += kernedWidth;\n }\n }\n currentColor &&\n textBgRects.push(\n createSVGInlineRect(\n lastColor,\n leftOffset + boxStart,\n textTopOffset,\n boxWidth,\n heightOfLine,\n ),\n );\n }\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(this: TextSVGExportMixin & FabricText, skipShadow?: boolean) {\n return `${super.getSvgStyles(skipShadow)} text-decoration-thickness: ${toFixed((this.textDecorationThickness * this.getObjectScaling().y) / 10, config.NUM_FRACTION_DIGITS)}%; white-space: pre;`;\n }\n\n /**\n * Returns styles-string for svg-export\n * @param {Object} style the object from which to retrieve style properties\n * @param {Boolean} useWhiteSpace a boolean to include an additional attribute in the style.\n * @return {String}\n */\n getSvgSpanStyles(\n this: TextSVGExportMixin & FabricText,\n style: TextStyleDeclaration,\n useWhiteSpace?: boolean,\n ) {\n const {\n fontFamily,\n strokeWidth,\n stroke,\n fill,\n fontSize,\n fontStyle,\n fontWeight,\n textDecorationThickness,\n linethrough,\n overline,\n underline,\n } = style;\n\n const textDecoration = this.getSvgTextDecoration({\n underline: underline ?? this.underline,\n overline: overline ?? this.overline,\n linethrough: linethrough ?? this.linethrough,\n });\n const thickness = textDecorationThickness || this.textDecorationThickness;\n return [\n stroke ? colorPropToSVG(STROKE, stroke) : '',\n strokeWidth ? `stroke-width: ${escapeXml(strokeWidth)}; ` : '',\n fontFamily\n ? `font-family: ${\n !fontFamily.includes(\"'\") && !fontFamily.includes('\"')\n ? `'${escapeXml(fontFamily)}'`\n : escapeXml(fontFamily)\n }; `\n : '',\n fontSize ? `font-size: ${escapeXml(fontSize)}px; ` : '',\n fontStyle ? `font-style: ${escapeXml(fontStyle)}; ` : '',\n fontWeight ? `font-weight: ${escapeXml(fontWeight)}; ` : '',\n textDecoration\n ? `text-decoration: ${textDecoration}; text-decoration-thickness: ${toFixed((thickness * this.getObjectScaling().y) / 10, config.NUM_FRACTION_DIGITS)}%; `\n : '',\n fill ? colorPropToSVG(FILL, fill) : '',\n useWhiteSpace ? 'white-space: pre; ' : '',\n ].join('');\n }\n\n /**\n * Returns text-decoration property for svg-export\n * @param {Object} style the object from which to retrieve style properties\n * @return {String}\n */\n getSvgTextDecoration(\n this: TextSVGExportMixin & FabricText,\n style: TextStyleDeclaration,\n ) {\n return (['overline', 'underline', 'line-through'] as const)\n .filter(\n (decoration) =>\n style[\n decoration.replace('-', '') as\n | 'overline'\n | 'underline'\n | 'linethrough'\n ],\n )\n .join(' ');\n }\n}\n"],"names":["multipleSpacesRegex","dblQuoteRegex","createSVGInlineRect","color","left","top","width","height","createSVGRect","TextSVGExportMixin","FabricObjectSVGExportMixin","_toSVG","offsets","this","_getSVGLeftTopOffsets","textAndBg","_getSVGTextAndBg","textTop","textLeft","_wrapSVGTextAndBg","toSVG","reviver","textSvg","_createBaseSVGMarkup","noStyle","withShadow","path","additionalTransform","matrixToSVG","calcOwnMatrix","lineTop","getHeightOfLine","_ref","textBgRects","textSpans","textDecoration","getSvgTextDecoration","join","escapeXml","fontFamily","replace","fontSize","fontStyle","fontWeight","direction","getSvgStyles","addPaintOrder","textTopOffset","textLeftOffset","lineOffset","backgroundColor","push","i","len","_textLines","length","_getLineLeftOffset","textBackgroundColor","styleHas","_setSVGTextLineBg","_setSVGTextLineText","_createTextCharSpan","char","styleDecl","charBox","numFractionDigit","config","NUM_FRACTION_DIGITS","styleProps","getSvgSpanStyles","trim","match","fillStyles","dy","deltaY","dySpan","toFixed","angle","renderLeft","renderTop","angleAttr","undefined","wBy2","radiansToDegrees","m","createRotateMatrix","renderPoint","Point","transform","x","y","lineIndex","lineHeight","isJustify","textAlign","includes","JUSTIFY","line","actualStyle","nextStyle","style","timeToRender","charsToRender","boxWidth","_fontSizeFraction","charSpacing","__charBounds","kernedWidth","_reSpaceAndTab","test","getCompleteStyleDeclaration","hasStyleChanged","_getStyleDeclaration","leftOffset","heightOfLine","currentColor","boxStart","lastColor","getValueOfPropertyAt","j","skipShadow","super","textDecorationThickness","getObjectScaling","useWhiteSpace","strokeWidth","stroke","fill","linethrough","overline","underline","thickness","colorPropToSVG","STROKE","FILL","filter","decoration"],"mappings":"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"}