我有覆盖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];
}
});
间距效果不错,但宽度不正确,如何改善宽度计算?
我已经在这个问题上改进了我的代码,现在它工作正常))
很抱歉没有显示以前的错误,但是这里很难做出明确的鳕鱼,而且我在此问题上有正确的答案。
但我已将其写为左对齐文本,如果使用不同的对齐,则需要更正它。对我来说就足够了
答案 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/