文本绘制:fillText与strokeText
文本绘制,说白了就是在Canvas上写字。我刚开始接触Canvas时,觉得这有什么难的?不就是写几个字嘛。但实际做项目才发现,文本渲染的坑比想象中多得多。
Canvas提供了两种绘制文本的方式:fillText和strokeText。前者是填充文字,后者是描边文字。你可以理解为——一个是用毛笔写,一个是用钢笔勾轮廓。
fillText:填充文字
这是最常用的方法。用法很简单:
ctx.fillText('Hello Canvas', x, y);
三个参数:要显示的文本、x坐标、y坐标。注意,这里的y坐标是文本基线的位置,不是文字顶部。我刚开始就犯过这个错,以为y是文字左上角,结果文字全跑偏了。
你可以先设置字体和颜色:
ctx.font = '24px Arial';
ctx.fillStyle = '#ff6600';
ctx.fillText('Canvas动画开发', 100, 100);
strokeText:描边文字
描边文字只画轮廓,不填充内部。用法和fillText一样:
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
ctx.strokeText('描边文字', 100, 200);
我在项目中遇到过一种情况:需要做文字特效,先描边再填充,让文字看起来有立体感。做法就是先画描边,再在上面画填充,注意偏移几个像素:
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.strokeText('立体效果', 100, 300);
ctx.fillStyle = '#fff';
ctx.fillText('立体效果', 100, 300);
字体设置:font属性
ctx.font的语法和CSS的font属性基本一致。格式是:
ctx.font = 'font-style font-variant font-weight font-size/line-height font-family';
但说实话,在Canvas里你不需要写那么全。我一般只写字号和字体族:
ctx.font = '20px "Microsoft YaHei", sans-serif';
常用的写法:
'16px Arial'— 基础用法'bold 24px "Microsoft YaHei"'— 加粗+字号+字体'italic 18px "Times New Roman"'— 斜体'600 32px "PingFang SC", sans-serif'— 字重用数字
文本对齐:textAlign
文本对齐控制的是文字在水平方向上的定位方式。取值有:
| 值 | 说明 | 实际效果 |
|---|---|---|
start |
默认值,从左到右文本左对齐 | 文字从指定点开始向右排 |
end |
从右到左文本右对齐 | 文字在指定点左侧结束 |
left |
左对齐 | 和start在LTR下相同 |
right |
右对齐 | 和end在LTR下相同 |
center |
居中对齐 | 文字中心在指定点上 |
举个例子:
ctx.textAlign = 'center';
ctx.fillText('居中文字', 200, 100);
ctx.textAlign = 'right';
ctx.fillText('右对齐', 200, 150);
我个人习惯在做图表标注时用center,做列表文字时用start或left。你想想看,如果柱状图顶部要显示数值,用center对齐是不是最省心?
文本基线:textBaseline
这个属性控制的是文字在垂直方向上的对齐方式。我敢说,80%的Canvas新手都在这里栽过跟头。
取值有:
| 值 | 说明 |
|---|---|
alphabetic |
默认值,字母基线 |
top |
文字顶部对齐 |
hanging |
悬挂基线(用于印度文等) |
middle |
文字中部对齐 |
ideographic |
表意文字基线(用于中文、日文) |
bottom |
文字底部对齐 |
为什么会有这么多基线?因为不同语言的文字,视觉重心不一样。英文的基线在字母底部,中文的基线在底部偏上一点。
我建议你在做中文项目时,直接用top或middle。为什么?因为alphabetic会让中文偏上,看起来不居中。我曾经做一个答题App,文字在按钮里总是偏上,调了半天才发现是基线的问题。
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText('完美居中', canvas.width / 2, canvas.height / 2);
textAlign = 'center'和textBaseline = 'middle',然后坐标取矩形中心点。这是最稳妥的做法。
measureText:测量文本
有时候你需要知道一段文字到底占多宽。比如做自适应排版、文字截断、气泡框等场景。
measureText方法返回一个TextMetrics对象,里面包含文字的宽度信息:
const metrics = ctx.measureText('Hello Canvas');
console.log(metrics.width); // 输出像素宽度
注意,它只能测量宽度,不能测量高度。为什么?因为Canvas的文本高度取决于字体大小和基线,没有直接API获取。我一般用字号乘以1.2来估算行高。
实际应用场景:
const text = '这是一段需要截断的文字';
const maxWidth = 200;
ctx.font = '16px "Microsoft YaHei"';
if (ctx.measureText(text).width > maxWidth) {
// 截断处理
let truncated = text;
while (ctx.measureText(truncated + '...').width > maxWidth) {
truncated = truncated.slice(0, -1);
}
ctx.fillText(truncated + '...', 50, 100);
} else {
ctx.fillText(text, 50, 100);
}
还有一个冷知识:TextMetrics对象除了width,还有actualBoundingBoxAscent和actualBoundingBoxDescent,这两个属性可以帮你计算文字的实际高度。不过浏览器兼容性一般,生产环境慎用。
嗯,文本绘制这块内容就这些。说白了就是四个核心点:怎么画、用什么字体、怎么对齐、怎么测量。掌握了这些,Canvas文本操作基本就通了。下一章我们会讲图像绘制,到时候你会看到文本和图像结合能玩出什么花样来。