文本和图像混合也是常见的绘制需求,因此 2D 绘图上下文还提供了绘制文本的方法,即 fillText() 和 strokeText()。这两个方法都接收 4 个参数:要绘制的字符串、x 坐标、y 坐标和可选的最大像素 宽度。而且,这两个方法最终绘制的结果都取决于以下 3 个属性。
font:以 CSS 语法指定的字体样式、大小、字体族等,比如"10px Arial"。
textAlign:指定文本的对齐方式,可能的值包括"start"、“end”、“left”、“right"和 “center”。推荐使用"start"和"end”,不使用"left"和"right",因为前者无论在从左到右
书写的语言还是从右到左书写的语言中含义都更明确。
textBaseLine: 指 定 文 本 的 基 线 , 可 能 的 值 包 括"top"、“hanging”、“middle”、
“alphabetic”、“ideographic"和"bottom”。 这些属性都有相应的默认值,因此没必要每次绘制文本时都设置它们。fillText()方法使用
fillStyle 属性绘制文本,而 strokeText()方法使用 strokeStyle 属性。通常,fillText()方法 是使用最多的,因为它模拟了在网页中渲染文本。例如,下面的例子会在前一节示例的表盘顶部绘制数 字“12”:
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12", 100, 20);
因为把 textAlign 设置为了"center",把 textBaseline 设置为了"middle",所以(100, 20)表 示文本水平和垂直中心点的坐标。如果 textAlign 是"start",那么 x 坐标在从左到右书写的语言中 表示文本的左侧坐标,而"end"会让 x 坐标在从左到右书写的语言中表示文本的右侧坐标。例如:
// 正常
context.font = "bold 14px Arial"; context.textAlign = "center"; context.textBaseline = "middle"; context.fillText("12", 100, 20); // 与开头对齐
context.textAlign = "start"; context.fillText("12", 100, 40); // 与末尾对齐
context.textAlign = "end"; context.fillText("12", 100, 60);
2D 绘图上下文
字符串"12"被绘制了 3 次,每次使用的坐标都一样,但 textAlign 值不同。为了让每个字符串不
至于重叠,每次绘制的 y 坐标都会设置得大一些。结果就是图像。
因为表盘中垂直的线条是居中的,所以文本的对齐方式就一目了然了。类似地,通过修改 textBaseline 19 属性,可以改变文本的垂直对齐方式。比如,设置为"top"意味着 y 坐标表示文本顶部,"bottom"表示 文本底部,“hanging”、"alphabetic"和"ideographic"分别引用字体中特定的基准点。
由于绘制文本很复杂,特别是想把文本绘制到特定区域的时候,因此 2D 上下文提供了用于辅助确 20 定文本大小的 measureText()方法。这个方法接收一个参数,即要绘制的文本,然后返回一个
TextMetrics 对象。这个返回的对象目前只有一个属性 width,不过将来应该会增加更多度量指标。 measureText()方法使用 font、textAlign 和 textBaseline 属性当前的值计算绘制指定文本 后的大小。例如,假设要把文本"Hello world!"放到一个 140 像素宽的矩形中,可以使用以下代码,
从 100 像素的字体大小开始计算,不断递减,直到文本大小合适:
let fontSize = 100;
context.font = fontSize + "px Arial";
while(context.measureText("Hello world!").width > 140) {
fontSize--;
context.font = fontSize + "px Arial";
}
context.fillText("Hello world!", 10, 10);
context.fillText("Font size is " + fontSize + "px", 10, 50);
fillText()和 strokeText()方法还有第四个参数,即文本的最大宽度。这个参数是可选的 (Firefox 4 是第一个实现它的浏览器),如果调用 fillText()和 strokeText()时提供了此参数,但要 绘制的字符串超出了最大宽度限制,则文本会以正确的字符高度绘制,这时字符会被水平压缩,以达到绘制文本是一项比较复杂的操作,因此支持元素的浏览器不一定全部实现了相关的文本 绘制 API。
动画与 Canvas 图形
上下文变换可以操作绘制在画布上的图像。2D 绘图上下文支持所有常见的绘制变换。在创建绘制 上下文时,会以默认值初始化变换矩阵,从而让绘制操作如实应用到绘制结果上。对绘制上下文应用变 换,可以导致以不同的变换矩阵应用绘制操作,从而产生不同的结果。
以下方法可用于改变绘制上下文的变换矩阵。
rotate(angle):围绕原点把图像旋转 angle 弧度。
scale(scaleX, scaleY):通过在 x 轴乘以 scaleX、在 y 轴乘以 scaleY 来缩放图像。scaleX
和 scaleY 的默认值都是 1.0。
translate(x, y):把原点移动到(x, y)。执行这个操作后,坐标(0, 0)就会变成(x, y)。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy):像下面这样通过矩阵乘法直接修改矩阵。
m1_1 m1_2 dx m2_1 m2_2 dy 001
setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):把矩阵重置为默认值,再以传入的 参数调用 transform()。
变换可以简单,也可以复杂。例如,在前面绘制表盘的例子中,如果把坐标原点移动到表盘中心,
那再绘制表针就非常简单了:
let drawing = document.getElementById("drawing");
// 确保浏览器支持<canvas> if (drawing.getContext) {
let context = drawing.getContext("2d");
// 创建路径 context.beginPath();
// 绘制外圆
context.arc(100, 100, 99, 0, 2 * Math.PI, false);
// 绘制内圆
context.moveTo(194, 100);
context.arc(100, 100, 94, 0, 2 * Math.PI, false);
// 移动原点到表盘中心 context.translate(100, 100);
// 绘制分针 context.moveTo(0, 0); context.lineTo(0, -85);
// 绘制时针 context.moveTo(0, 0); context.lineTo(-65, 0);
// 描画路径
context.stroke();
}