Fabricjs文本间距

时间:2015-05-17 17:00:52

标签: fabricjs

我有覆盖fabricjs文本对象以使字母间距

fabric.util.object.extend(fabric.Text.prototype, {
    letterSpace: 0,
    _renderChars: function(method, ctx, chars, left, top) {
        if(!this.letterSpace){
            ctx[method](chars, left, top);
            return;
        }
        var charShift = 0;
        for(var i = 0; i < chars.length; i++){
            if(i > 0){
                charShift += this.letterSpace + ctx.measureText(chars.charAt(i-1)).width;
           }
           ctx[method](chars.charAt(i), left+charShift, top);
       }
    },
    _getLineWidth: function(ctx, lineIndex) {
        if (this.__lineWidths[lineIndex]) {
            return this.__lineWidths[lineIndex];
        }
        var lineLength = this._textLines[lineIndex].length;
        var additionalSpaceSum = 0
        if(lineLength > 0){
            additionalSpaceSum = this.letterSpace * (lineLength - 1);
        }
        this.__lineWidths[lineIndex] = ctx.measureText(this._textLines[lineIndex]).width + additionalSpaceSum;
        return this.__lineWidths[lineIndex];
    }
});

间距效果不错,但宽度不正确,如何改善宽度计算?

我已经在这个问题上改进了我的代码,现在它工作正常))

很抱歉没有显示以前的错误,但是这里很难做出明确的鳕鱼,而且我在此问题上有正确的答案。

但我已将其写为左对齐文本,如果使用不同的对齐,则需要更正它。对我来说就足够了

3 个答案:

答案 0 :(得分:0)

我已经改进了我的代码,现在它工作正常))抱歉。

但我已将其写为左对齐文本,如果使用不同的对齐,则需要更正它。对我来说就足够了

fabric.util.object.extend(fabric.Text.prototype, {
    letterSpace: 0,
    _renderChars: function (method, ctx, chars, left, top) {
        if (!this.letterSpace) {
            ctx[method](chars, left, top);
            return;
        }
        var charShift = 0;
        for (var i = 0; i < chars.length; i++) {
            if (i > 0) {
                charShift += this.letterSpace + ctx.measureText(chars.charAt(i - 1)).width;
            }
            ctx[method](chars.charAt(i), left + charShift, top);
        }
    },
    _getLineWidth: function (ctx, lineIndex) {
        var lineLength = this._textLines[lineIndex].length;
        var additionalSpaceSum = 0
        if (lineLength > 0) {
            additionalSpaceSum = this.letterSpace * (lineLength - 1);
        }
        this.__lineWidths[lineIndex] = ctx.measureText(this._textLines[lineIndex]).width + additionalSpaceSum;
        return this.__lineWidths[lineIndex];
    },
    _renderExtended: function (ctx) {
        this.clipTo && fabric.util.clipContext(this, ctx);
        this.extendedRender = true;
        this._renderTextBackground(ctx);
        this._renderText(ctx);

        this._renderTextDecoration(ctx);
        this.clipTo && ctx.restore();
    }
});

答案 1 :(得分:0)

此代码适用于所有路线:

fabric.util.object.extend(fabric.Text.prototype, {
letterSpace: 0,
_renderChars: function (method, ctx, chars, left, top) {
    if (!this.letterSpace) {
        ctx[method](chars, left, top);
        return;
    }
    var characters = String.prototype.split.call(chars, '');
    if(this.textAlign == 'left'){
        var charShift = 0;
        for (var i = 0; i < chars.length; i++) {
            if (i > 0) {
                charShift += this.letterSpace + ctx.measureText(chars.charAt(i - 1)).width;
            }
            ctx[method](chars.charAt(i), left + charShift, top);
        }    
    }else if(this.textAlign == 'right'){

        characters.reverse();
        chars = characters.join('');
        var charShift = 0;
        for (var i = 0; i < chars.length; i++) {
            if (i > 0) {
                charShift += this.letterSpace + ctx.measureText(chars.charAt(i - 1)).width;
            }
            ctx[method](chars.charAt(i), left - charShift, top);
        }    
    }else if(this.textAlign == 'center'){

        var totalWidth = 0;
        for (var i = 0; i < characters.length; i++) {
            totalWidth += (ctx.measureText(characters[i]).width + this.letterSpace);
        }
        var currentPosition = left - (totalWidth / 2);


        var charShift = 0;
        for (var i = 0; i < chars.length; i++) {
            if (i > 0) {
                charShift += this.letterSpace + ctx.measureText(chars.charAt(i - 1)).width;
            }
            ctx[method](chars.charAt(i), currentPosition + left + charShift, top);
        }    
    }

},
_getLineWidth: function (ctx, lineIndex) {
    var lineLength = this._textLines[lineIndex].length;
    var additionalSpaceSum = 0
    if (lineLength > 0) {
        additionalSpaceSum = this.letterSpace * (lineLength - 1);
    }
    this.__lineWidths[lineIndex] = ctx.measureText(this._textLines[lineIndex]).width + additionalSpaceSum;
    return this.__lineWidths[lineIndex];
},
_renderExtended: function (ctx) {
    this.clipTo && fabric.util.clipContext(this, ctx);
    this.extendedRender = true;
    this._renderTextBackground(ctx);
    this._renderText(ctx);

    this._renderTextDecoration(ctx);
    this.clipTo && ctx.restore();
}});

以下是一个示例:http://jsfiddle.net/peybdq94/

答案 2 :(得分:0)

我尝试实现此功能,并通过扩展_renderChar来提出此https://jsfiddle.net/ghazaltaimur/bx0f4qpg/1/。我做了几个补充。该代码允许字母间距应用于所选文本而不是仅应用于整个对象。如果要添加字母间距,则必须考虑填充迭代选择,边界框和光标位置。我也试图涵盖这些方面。可能还有一些问题需要修复。

    fabric.util.object.extend(fabric.IText.prototype, {
      letterSpace: 0,
      _renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) {
        var decl, charWidth, charHeight,
          offset = this._fontSizeFraction * lineHeight / this.lineHeight;
        if (this.styles && this.styles[lineIndex] && (decl = this.styles[lineIndex][i])) {
          var shouldStroke = decl.stroke || this.stroke,
            shouldFill = decl.fill || this.fill;
          ctx.save();
          charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i, decl);
          charHeight = this._getHeightOfChar(ctx, _char, lineIndex, i);
          var chars = _char;
          var characters = String.prototype.split.call(chars, '');
          var charShift = 0;
          var leftcharShift = 0;
          var letterSpace;
          for (var i = 0; i < chars.length; i++) {
            var style = this.getCurrentCharStyle(lineIndex, i + 1);
            letterSpace = style.letterSpace;
            if (i > 0) {
              charShift += parseInt(letterSpace) + parseInt(ctx.measureText(chars.charAt(i - 1)).width);
            }
            if (this.text.indexOf(chars) !== 0 && charShift === 0) {
              charShift = this.text.indexOf(chars) * parseInt(letterSpace);
            }
            leftcharShift = parseInt(left) + parseInt(charShift);
            if (shouldFill) {
              ctx.fillText(chars.charAt(i), leftcharShift, top);
            }
            if (shouldStroke) {
              ctx.strokeText(chars.charAt(i), leftcharShift, top);
            }
          }
          this._renderCharDecoration(ctx, decl, left, top, offset, charWidth, charHeight);
          ctx.restore();
          ctx.translate(charWidth, 0);
        } else {
          charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i);
          var chars = _char;
          var characters = String.prototype.split.call(chars, '');
          var charShift = 0;
          var leftcharShift = 0;
          var letterSpace;
          for (var i = 0; i < chars.length; i++) {
            var style = this.getCurrentCharStyle(lineIndex, i + 1);
            letterSpace = style.letterSpace;
            if (i > 0) {
              charShift += parseInt(letterSpace) + parseInt(ctx.measureText(chars.charAt(i - 1)).width);
            }
            if (this.text.indexOf(chars) !== 0 && charShift === 0) {
              charShift = this.text.indexOf(chars) * parseInt(letterSpace);
            }
            leftcharShift = parseInt(left) + parseInt(charShift);
            if (method === 'strokeText' && this.stroke) {
              ctx[method](chars.charAt(i), leftcharShift, top);
            }
            if (method === 'fillText' && this.fill) {
              ctx[method](chars.charAt(i), leftcharShift, top);
            }
          }
          this._renderCharDecoration(ctx, null, left, top, offset, charWidth, this.fontSize);
          ctx.translate(ctx.measureText(_char).width, 0);
        }},
    getCurrentCharStyle: function(lineIndex, charIndex) {
        var style = this.styles[lineIndex] && this.styles[lineIndex][charIndex === 0 ? 0 : (charIndex - 1)];
        return {
          fontSize: style && style.fontSize || this.fontSize,
          fill: style && style.fill || this.fill,
          textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor,
          textDecoration: style && style.textDecoration || this.textDecoration,
          fontFamily: style && style.fontFamily || this.fontFamily,
          fontWeight: style && style.fontWeight || this.fontWeight,
          fontStyle: style && style.fontStyle || this.fontStyle,
          stroke: style && style.stroke || this.stroke,
          strokeWidth: style && style.strokeWidth || this.strokeWidth,
          letterSpace: style && style.letterSpace || this.letterSpace
        };
      },
      _renderTextLine: function(method, ctx, line, left, top, lineIndex) {
        // to "cancel" this.fontSize subtraction in fabric.Text#_renderTextLine
        // the adding 0.05 is just to align text with itext by overlap test
        if (!this.isEmptyStyles()) {
          top += this.fontSize * (this._fontSizeFraction + 0.05);
        }
        this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex);
      },
      _getWidthOfChar: function(ctx, _char, lineIndex, charIndex) {
        if (this.textAlign === 'justify' && /\s/.test(_char)) {
          return this._getWidthOfSpace(ctx, lineIndex);
        }

var styleDeclaration = this._getStyleDeclaration(lineIndex, charIndex); this._applyFontStyles(styleDeclaration); var cacheProp = this._getCacheProp(_char, styleDeclaration); var style = this.getCurrentCharStyle(lineIndex, charIndex); var letterSpace = style.letterSpace; if (this._charWidthsCache[cacheProp] && this.caching) { return parseInt(this._charWidthsCache[cacheProp]) + parseInt(letterSpace); } else if (ctx) { ctx.save(); var width = this._applyCharStylesGetWidth(ctx, _char, lineIndex, charIndex); width = parseInt(width) + parseInt(letterSpace); ctx.restore(); return width; } }, }); // fabric js code var canvas = new fabric.Canvas('fabric_canvas'); // add text fabric.util.addListener(document.getElementById('addText'), 'click', function() { var itext = new fabric.IText("Add text", { left: 50, top: 50 }); canvas.add(itext); canvas.setActiveObject(itext); var obj = canvas.getActiveObject(); var seletedText = obj.getSelectedText(); itext.selectAll(); itext.enterEditing(); if (obj.setSelectionStyles && obj.isEditing) obj.setSelectionStyles({ letterSpace: 1 }); if (seletedText === "") { obj.exitEditing(); } canvas.renderAll(); }); // add letter spacing fabric.util.addListener(document.getElementById('addLetterSpacing'), 'click', function() { var activeObject = canvas.getActiveObject(); var seletedText = activeObject.getSelectedText(); if (seletedText === "") { activeObject.selectAll(); activeObject.enterEditing(); } if (activeObject.setSelectionStyles && activeObject.isEditing) activeObject.setSelectionStyles({ letterSpace: 30 }); if (seletedText === "") { activeObject.exitEditing(); } var ctx = activeObject.ctx; var textLines = activeObject.text.split(activeObject._reNewline); var letterSpace = (activeObject.getSelectionStyles && activeObject.isEditing && activeObject.evented === true) ? activeObject.getSelectionStyles()["letterSpace"] : activeObject["letterSpace"]; activeObject.width = activeObject._getTextWidth(ctx, textLines, activeObject) + (activeObject.text.length * letterSpace); activeObject.height = activeObject._getTextHeight(ctx, textLines, activeObject); activeObject.callSuper('setCoords'); canvas.renderAll(); }); </code></pre> [1]: https://jsfiddle.net/ghazaltaimur/bx0f4qpg/1/