Fabric.js 文本样式 textAlign = justify 两端对齐不生效,特别是单行文本

这个确实是很多人第一次用 Fabric.js 的 textAlign: 'justify' 时踩的坑。我来详细解释一下:
一、问题原因
Fabric.js 的 textAlign: 'justify' 目前 并不是完整实现的 CSS 两端对齐 。 它的对齐逻辑在源码中( fabric.Textbox 的 _wrapLine 和 _renderTextLines 方法)有这样的限制:
只有当文本是多行 (
\n分行),并且不是最后一行时,才会对行内空格进行等距分配。
也就是说:
- ✅ 有换行的多行文本中, 除最后一行外 可以被拉伸对齐;
- ❌ 单行文本 或 自动换行但无显式换行符的行,不会触发 justify;
- ❌
textAlign: 'justify'对普通fabric.Text对象无效,只对fabric.Textbox有部分支持。
二、举个例子
const textbox = new fabric.Textbox(
'这是一段测试文本\n 用于展示 justify 对齐效果\n 最后一行不会被对齐',
{
left: 100,
top: 100,
width: 300,
textAlign: 'justify',
fontSize: 20,
fill: '#333',
}
);
canvas.add(textbox);✅ 前两行会被两端对齐, ❌ 最后一行不会被对齐。
三、如果你用的是 自动换行 :
比如:
new fabric.Textbox('这是一段比较长的文字希望自动换行并且两端对齐', {
width: 300,
textAlign: 'justify',
});Fabric.js 不会在渲染时真正 检测宽度自动分词对齐 , 因为它没有实现 CSS 的测量逻辑。 所以即使超出宽度换行,仍然不会 justify。
四、解决方法
其实我们很多时候需要的是,单行文本也能实现两端对齐,且不需要换行符,而且默认也是按照空格来分割间隔,对于中文文本来说,基本无效,我们可以修改 _renderTextLine 源码,让它不只按空格分词,而是按字符分布间距 。
// ===== Fabric.js 5.2.1 Justify Fix =====
const originalRenderTextLine = fabric.Textbox.prototype._renderTextLine;
fabric.Textbox.prototype._renderTextLine = function (method, ctx, line, left, top, lineIndex) {
const isLastLine = this._textLines ? lineIndex === this._textLines.length - 1 : false;
const isJustify = this.textAlign === 'justify';
// const isJustify = this.textAlign === 'justify' && !isLastLine;
if (!isJustify) {
return originalRenderTextLine.call(this, method, ctx, line, left, top, lineIndex);
}
const render = (text, x, y) => {
if (typeof ctx[method] === 'function') ctx[method](text, x, y);
else ctx.fillText(text, x, y);
};
ctx.save();
ctx.textBaseline = 'alphabetic'; // Fabric 默认基线
// 检查是否有空格
const hasSpace = /\s/.test(line);
const tokens = hasSpace ? line.split(/\s+/).filter(Boolean) : Array.from(line);
const gapCount = tokens.length - 1;
if (gapCount <= 0) {
ctx.restore();
return originalRenderTextLine.call(this, method, ctx, line, left, top, lineIndex);
}
// 计算宽度
const measure = t => ctx.measureText(t).width;
const widths = tokens.map(measure);
const totalWidth = widths.reduce((a, b) => a + b, 0);
const extra = (this.width - totalWidth) / gapCount;
// 关键:计算 baseline 偏移量
// Fabric 内部的行高包含 ascent+descent,而 fillText 以 baseline 绘制
// 我们通过 fontSize × (1 - lineHeightRatio) / 2 来补偿
const lineHeight = this.getHeightOfLine(lineIndex);
const fontSize = this.fontSize * (this._fontSizeMult || 1);
const baselineOffset = (lineHeight - fontSize) / 2 - fontSize * 0.3; // 经验值调试
const y = top + baselineOffset;
let x = left;
for (let i = 0; i < tokens.length; i++) {
render(tokens[i], x, y);
x += widths[i] + extra;
}
ctx.restore();
};将这个代码放置到引入 Fabric.js 之后即可,当给图层设置 textAlign = 'justify' 即可实现两端对齐。
发布评论
发布评论前请先 登录。
评论列表 0

暂无评论





