UNPKG

fabric-pure-browser

Version:

Fabric.js package with no node-specific dependencies (node-canvas, jsdom). The project is published once a day (in case if a new version appears) from 'master' branch of https://github.com/fabricjs/fabric.js repository. You can keep original imports in

242 lines (225 loc) 8.57 kB
/* _TO_SVG_START_ */ (function() { var toFixed = fabric.util.toFixed, multipleSpacesRegex = / +/g; fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ { /** * Returns SVG representation of an instance * @param {Function} [reviver] Method for further parsing of svg representation. * @return {String} svg representation of an instance */ _toSVG: function() { var offsets = this._getSVGLeftTopOffsets(), textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft); return this._wrapSVGTextAndBg(textAndBg); }, /** * Returns svg representation of an instance * @param {Function} [reviver] Method for further parsing of svg representation. * @return {String} svg representation of an instance */ toSVG: function(reviver) { return this._createBaseSVGMarkup( this._toSVG(), { reviver: reviver, noStyle: true, withShadow: true } ); }, /** * @private */ _getSVGLeftTopOffsets: function() { return { textLeft: -this.width / 2, textTop: -this.height / 2, lineTop: this.getHeightOfLine(0) }; }, /** * @private */ _wrapSVGTextAndBg: function(textAndBg) { var noShadow = true, textDecoration = this.getSvgTextDecoration(this); return [ textAndBg.textBgRects.join(''), '\t\t<text xml:space="preserve" ', (this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g, '\'') + '" ' : ''), (this.fontSize ? 'font-size="' + this.fontSize + '" ' : ''), (this.fontStyle ? 'font-style="' + this.fontStyle + '" ' : ''), (this.fontWeight ? 'font-weight="' + this.fontWeight + '" ' : ''), (textDecoration ? 'text-decoration="' + textDecoration + '" ' : ''), 'style="', this.getSvgStyles(noShadow), '"', this.addPaintOrder(), ' >', textAndBg.textSpans.join(''), '</text>\n' ]; }, /** * @private * @param {Number} textTopOffset Text top offset * @param {Number} textLeftOffset Text left offset * @return {Object} */ _getSVGTextAndBg: function(textTopOffset, textLeftOffset) { var textSpans = [], textBgRects = [], height = textTopOffset, lineOffset; // bounding-box background this._setSVGBg(textBgRects); // text and text-background for (var i = 0, len = this._textLines.length; i < len; i++) { lineOffset = this._getLineLeftOffset(i); if (this.textBackgroundColor || this.styleHas('textBackgroundColor', i)) { this._setSVGTextLineBg(textBgRects, i, textLeftOffset + lineOffset, height); } this._setSVGTextLineText(textSpans, i, textLeftOffset + lineOffset, height); height += this.getHeightOfLine(i); } return { textSpans: textSpans, textBgRects: textBgRects }; }, /** * @private */ _createTextCharSpan: function(_char, styleDecl, left, top) { var shouldUseWhitespace = _char !== _char.trim() || _char.match(multipleSpacesRegex), styleProps = this.getSvgSpanStyles(styleDecl, shouldUseWhitespace), fillStyles = styleProps ? 'style="' + styleProps + '"' : '', dy = styleDecl.deltaY, dySpan = '', NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; if (dy) { dySpan = ' dy="' + toFixed(dy, NUM_FRACTION_DIGITS) + '" '; } return [ '<tspan x="', toFixed(left, NUM_FRACTION_DIGITS), '" y="', toFixed(top, NUM_FRACTION_DIGITS), '" ', dySpan, fillStyles, '>', fabric.util.string.escapeXml(_char), '</tspan>' ].join(''); }, _setSVGTextLineText: function(textSpans, lineIndex, textLeftOffset, textTopOffset) { // set proper line offset var lineHeight = this.getHeightOfLine(lineIndex), isJustify = this.textAlign.indexOf('justify') !== -1, actualStyle, nextStyle, charsToRender = '', charBox, style, boxWidth = 0, line = this._textLines[lineIndex], timeToRender; textTopOffset += lineHeight * (1 - this._fontSizeFraction) / this.lineHeight; for (var i = 0, len = line.length - 1; i <= len; i++) { timeToRender = i === len || this.charSpacing; charsToRender += line[i]; charBox = this.__charBounds[lineIndex][i]; if (boxWidth === 0) { textLeftOffset += charBox.kernedWidth - charBox.width; boxWidth += charBox.width; } else { boxWidth += charBox.kernedWidth; } if (isJustify && !timeToRender) { if (this._reSpaceAndTab.test(line[i])) { timeToRender = true; } } if (!timeToRender) { // if we have charSpacing, we render char by char actualStyle = actualStyle || this.getCompleteStyleDeclaration(lineIndex, i); nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1); timeToRender = this._hasStyleChangedForSvg(actualStyle, nextStyle); } if (timeToRender) { style = this._getStyleDeclaration(lineIndex, i) || { }; textSpans.push(this._createTextCharSpan(charsToRender, style, textLeftOffset, textTopOffset)); charsToRender = ''; actualStyle = nextStyle; textLeftOffset += boxWidth; boxWidth = 0; } } }, _pushTextBgRect: function(textBgRects, color, left, top, width, height) { var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; textBgRects.push( '\t\t<rect ', this._getFillAttributes(color), ' x="', toFixed(left, NUM_FRACTION_DIGITS), '" y="', toFixed(top, NUM_FRACTION_DIGITS), '" width="', toFixed(width, NUM_FRACTION_DIGITS), '" height="', toFixed(height, NUM_FRACTION_DIGITS), '"></rect>\n'); }, _setSVGTextLineBg: function(textBgRects, i, leftOffset, textTopOffset) { var line = this._textLines[i], heightOfLine = this.getHeightOfLine(i) / this.lineHeight, boxWidth = 0, boxStart = 0, charBox, currentColor, lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor'); for (var j = 0, jlen = line.length; j < jlen; j++) { charBox = this.__charBounds[i][j]; currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor'); if (currentColor !== lastColor) { lastColor && this._pushTextBgRect(textBgRects, lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine); boxStart = charBox.left; boxWidth = charBox.width; lastColor = currentColor; } else { boxWidth += charBox.kernedWidth; } } currentColor && this._pushTextBgRect(textBgRects, currentColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine); }, /** * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values * we work around it by "moving" alpha channel into opacity attribute and setting fill's alpha to 1 * * @private * @param {*} value * @return {String} */ _getFillAttributes: function(value) { var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : ''; if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) { return 'fill="' + value + '"'; } return 'opacity="' + fillColor.getAlpha() + '" fill="' + fillColor.setAlpha(1).toRgb() + '"'; }, /** * @private */ _getSVGLineTopOffset: function(lineIndex) { var lineTopOffset = 0, lastHeight = 0; for (var j = 0; j < lineIndex; j++) { lineTopOffset += this.getHeightOfLine(j); } lastHeight = this.getHeightOfLine(j); return { lineTop: lineTopOffset, offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult) }; }, /** * Returns styles-string for svg-export * @param {Boolean} skipShadow a boolean to skip shadow filter output * @return {String} */ getSvgStyles: function(skipShadow) { var svgStyle = fabric.Object.prototype.getSvgStyles.call(this, skipShadow); return svgStyle + ' white-space: pre;'; }, }); })(); /* _TO_SVG_END_ */