Canvas 文本绘制:字体、对齐与测量
图形只是 Canvas 的一半,另一半是文本:标题、标签、坐标轴刻度、提示信息等等。
这一篇聚焦文本相关能力,围绕几个问题展开:如何控制字体与对齐方式、如何在高 DPI 下保持文字清晰、以及如何用文本测量来做简单布局。
1. 基本 API:fillText / strokeText 与 font
Canvas 里用于绘制文本的两个基础方法是:
fillText(text, x, y):使用当前填充样式绘制实心文本;strokeText(text, x, y):使用当前描边样式绘制描边文本。
文本样式主要由以下属性控制:
font:类似 CSS 的字体声明,例如"16px sans-serif";fillStyle/strokeStyle:文字颜色;textAlign:水平方向对齐方式;textBaseline:垂直方向基线对齐方式。
一个简单示例:
1ctx.font = "16px sans-serif";
2ctx.fillStyle = "#333";
3ctx.textAlign = "left"; // 默认
4ctx.textBaseline = "alphabetic"; // 默认
5ctx.fillText("Hello Canvas", x, y);
理解这些属性的组合,是后续做更复杂文本布局的基础。
2. textAlign 和 textBaseline:决定 (x, y) 在文字中的位置
2.1 水平对齐:textAlign
textAlign 决定 x 相对于文本的水平位置:
"left":x在文本左侧;"right":x在文本右侧;"center":x在文本水平中点;"start"/"end":根据文本方向决定,对大多数左到右语言,等价于"left"/"right"。
在绘制坐标轴刻度、按钮标签等场景中,合理使用水平对齐可以减少手动计算偏移。
2.2 垂直基线:textBaseline
textBaseline 决定 y 相对于文本垂直位置的关系:
"alphabetic"(默认):y对应普通西文字母基线;"top"/"hanging"/"middle"/"ideographic"/"bottom":分别对应不同的基线风格。
在实践中:
- 使用
"middle"搭配textAlign: 'center'可以方便地将文本居中放在某个点; - 在多语言场景,需要根据字体和排版需求选择合适的基线。
3. 文本清晰度与高 DPI 适配
在高 DPI 屏幕上,如果 Canvas 没有按 devicePixelRatio 调整尺寸,文本会被放大插值,显得发糊。
解决方案与图形类似:
- Canvas 的实际像素尺寸按
devicePixelRatio放大; - 使用
scale(dpr, dpr)调整坐标系; - 文本大小仍按逻辑像素指定(例如
"16px")。
这样可以:
- 让文本以更高的物理像素精度绘制;
- 避免浏览器对整个 Canvas 进行二次缩放。
在需要极高清晰度的场景(如小字体标注),可以适当增大小号字体并控制缩放,结合实际观察进行调整。
4. 文本测量:用 measureText 辅助布局
ctx.measureText(text) 返回一个 TextMetrics 对象,至少包含:
width:在当前font、textAlign和textBaseline下文本的宽度;
在简单布局中,可以利用这个宽度来:
- 实现单行文本的居中或右对齐(不依赖
textAlign时); - 计算文本与其他图形的间距;
- 做「超出宽度则截断/省略」的逻辑。
例如,一个简单的「在矩形中水平居中文本」可以是:
1const metrics = ctx.measureText(text);
2const textWidth = metrics.width;
3const x = rectX + (rectWidth - textWidth) / 2;
4const y = rectY + rectHeight / 2; // 再配合 textBaseline = 'middle'
5
6ctx.textBaseline = "middle";
7ctx.fillText(text, x, y);
对于多行文本与更精细布局:
- 通常需要在 JS 侧做文本分行和排版;
measureText可以用来估算每一行可容纳的字符数或宽度。
5. 文本与背景图形的协作:边界与留白
在很多图形场景中,文本不会单独存在,而是与矩形、圆形等图形配合使用:
- 按钮标签;
- 图表刻度与轴标签;
- 节点文字(流程图、脑图等)。
工程实践中的几点建议:
- 在封装组件时,把「绘制背景」和「绘制文本」拆成两个函数;
- 利用
measureText确定文本实际宽度,再给背景图形预留适量 padding; - 保持对齐逻辑在一个地方集中管理(例如一个
drawLabel工具函数)。
这样可以避免到处重复写对齐和间距计算,也方便后续统一调整样式。
6. 小结:把文本当成「一等公民」来看待
这一篇可以概括为几个关键点:
- Canvas 提供了
fillText/strokeText和一组字体/对齐属性,让可以在任意位置绘制文本; textAlign和textBaseline决定了 (x, y) 在文字中的含义,是做布局和对齐时必须搞清楚的;- 高 DPI 下需要配合整体 Canvas 尺寸缩放来保持文字清晰;
measureText是做单行文本布局的基础工具,复杂排版则需要在 JS 中自行分行和定位。
在掌握这些基础之后,Canvas 中的文字不再只是简单的标注,而可以参与到更复杂的布局与交互设计中。