本章摘要
本章节将介绍如何使用HTML5 Canvas API绘制和美化文字,包括设置颜色、字体、对齐方式,以及调整间距、添加阴影和实现垂直排列等高级技巧。通过学习,您将掌握Canvas中文本渲染的核心技术,提升图形开发能力,满足各种复杂的文本渲染需求。
![图形系统开发实战课程 - 基础篇 绘制文字](/assets/images/banner_f02.jpg)
第二章 绘制文字
本章的内容包括:
- 绘制常见的文本
- 文本的水平对齐
- 文本的垂直对齐
- 文本的间距
- 文本垂直排列
1. 绘制常见的文本
画布渲染上下文提供了两个api用于绘制文本:
1 2
| ctx.strokeText(text, x, y[, maxWidth]); ctx.fillText(text, x, y[, maxWidth]);
|
strokeText()
是用于绘制文本外框,而fillText()
是填充文本。我们先看一下绘制结果:
![执行效果](./image_a2/1-1.png)
绘制填充文字
我们日常见到的文字就是填充的文字,通过fillText()
方法,就能够直接在画布中绘制填充的文字。其代码为:
1 2
| ctx.font = "40px 黑体"; ctx.fillText("绘制普通中文和English文字", 50, 80);
|
Canvas通过font属性指定字体大小和字体名称,其格式和css样式中用法的一致,这里的文字大小通常指的就是文字的高度,其单位为像素(px)。
绘制空心文字
在画布中绘制空心文字也很简单,只需通过strokeText()
方法即可实现,其代码如下:
1 2
| ctx.font = "40px 黑体"; ctx.strokeText("绘制空心中文和English文字", 50, 150);
|
绘制空心文字还可以通过线宽lineWidth
属性指定边框的大小,其效果如下图所示:
![执行效果](./image_a2/1-2.png)
源代码如下:
1 2 3 4 5 6 7 8
| ctx.font = "40px 黑体"; ctx.lineWidth = 1; ctx.strokeText("边框粗细", 60, 60); ctx.lineWidth = 2; ctx.strokeText("边框粗细", 260, 60); ctx.lineWidth = 3; ctx.strokeText("边框粗细", 460, 60);
|
尝试一下 »
指定字体的其他样式
渲染上下文对象还提供了一些属性可以设置字体、字号、粗体、斜体、文字颜色等样式。
属性名称 |
说明 |
ctx.font |
设置字体属性,包括字体、字号、粗细、斜体等样式 |
ctx.fillStyle |
设置字体颜色 |
ctx.strokeStyle |
设置在绘制空心文字时边框的大小 |
下面这个示例设置几种字体和字号,并设置了粗体和斜体,其效果如下图所示:
![执行效果](./image_a2/1-3.png)
源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "40px 黑体"; ctx.fillText("40px黑体", 40, 60); ctx.font = "30px 楷体"; ctx.fillText("30px楷体", 280, 60); ctx.fillStyle = "red"; ctx.font = "bold 22px 仿宋"; ctx.fillText("22px加粗仿宋", 460, 60); ctx.font = "italic 22px 仿宋"; ctx.fillText("22px斜体仿宋", 640, 60);
ctx.font = "italic 40px 黑体"; ctx.strokeText("40px黑体", 40, 130); ctx.font = "30px 楷体"; ctx.strokeText("30px楷体", 280, 130); ctx.strokeStyle = "blue"; ctx.font = "22px 仿宋"; ctx.strokeText("22px仿宋", 460, 130); ctx.font = "16px 仿宋"; ctx.strokeText("16px仿宋", 640, 130); </script>
|
尝试一下 »
以下为设置字体为粗体或斜体的写法:
将字体设置为粗体: ctx.font = "bold 22px 仿宋"
将字体设置为斜体: ctx.font = "italic 22px 仿宋"
将字体设置为加粗和斜体: ctx.font = "bold italic 22px 仿宋"
绘制带阴影的文字
画布渲染上下文直接提供了shadowColor
和shadBlur
等属性,可实现绘制带阴影的文字,这几个属性的说明如下:
属性 |
说明 |
shadowBlur |
模糊效果程度 |
shadowColor |
阴影颜色 |
shadowOffsetX |
阴影水平偏移距离,默认值是 0。 |
shadowOffsetY |
阴影垂直偏移距离,默认值是 0。 |
下面这个示例绘制了几个带阴影的文字,其效果如下图所示:
![执行效果](./image_a2/1-4.png)
源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.save(); ctx.shadowColor = "#000000"; ctx.shadowBlur = 8; ctx.font = "40px 黑体"; ctx.fillText("文字阴影效果1", 50, 70);
ctx.shadowBlur = 4; ctx.fillText("文字阴影效果2", 420, 70);
ctx.shadowColor = "#FF0000"; ctx.shadowOffsetX = 3; ctx.fillText("文字阴影效果3", 50, 140);
ctx.shadowOffsetY = 3; ctx.fillText("文字阴影效果4", 420, 140); </script>
|
尝试一下 »
绘制带背景的文字
带背景的文字其实是绘制了一次空心文字和一次填充文字,且在绘制空心文字时需要将线宽指定大一点,其代码如下:
1 2 3 4 5 6
| ctx.font = "22px 黑体"; ctx.lineWidth = 5; ctx.strokeStyle = "#CCCCCC"; ctx.strokeText("带背景的文字", 100, 310); ctx.fillStyle="#000000"; ctx.fillText("带背景的文字", 100, 310);
|
带背景的文字通常应用在背景比较复杂的图形中,例如地理图或包含了多种颜色的图像,这类图形有可能是浅色背景,也有可能是深色背景,给文字添加了背景后,就能够直观突出文字了,如下图中的滤镜名称就应用了这种文字效果。
![执行效果](./image_a2/1-5.png)
2. 水平对齐
在office word中排版时,我们经常会用到文字水平对齐功能,Canvas也提供了类似的功能(其实word本质上也是一个使用绘图功能开发出来的应用软件)。画布渲染上下文提供了textAlign
属性,可指定文字的水平对齐方式,该属性可选择以下几个值:
属性 |
说明 |
left |
文本左对齐 |
right |
文本右对齐 |
center |
文本居中对齐 |
start |
默认值,文本对齐界线开始的地方(左对齐指本地从左向右,右对齐指本地从右向左) |
end |
文本对齐界线结束的地方(左对齐指本地从左向右,右对齐指本地从右向左) |
我们看一下各种水平对齐方式的运行效果,如下图所示:
![执行效果](./image_a2/2-1.png)
textAlign=“left”
文本左对齐比较好理解,指的是在水平方向从给定的x坐标值开始,将文字字符串从左向右延伸排列。注意上图中红点表示的坐标(x,y)位置。
1 2 3
| ctx.textAlign = "left"; ctx.fillText("文字的水平对齐(left)", 300, 60);
|
textAlign=“center”
文本居中对齐指的是在水平方向从给定的x坐标值开始,将文字字符串居中向两端排列(也就是说文本一半在x的左边,一半在x的右边)。注意上图中红点表示的坐标(x,y)位置。
1 2 3
| ctx.textAlign = "center"; ctx.fillText("文字的水平对齐(center)", 300, 110);
|
textAlign=“right”
文本右对齐指的是在水平方向从给定的x坐标值开始,将文字字符串从右向左延伸排列。注意上图中红点表示的坐标(x,y)位置。
1 2 3
| ctx.textAlign = "right"; ctx.fillText("文字的水平对齐(right)", 300, 160);
|
textAlign=“start”
该值为默认缺省值,当没有设置文字方向ctx.direction
属性或ctx.direction="ltr"
时,其运行效果与ctx.textAlign = "left"
一样;当ctx.direction="rtl"
时,其运行效果与ctx.textAlign = "right"
一样。
1 2 3 4 5 6
| ctx.textAlign = "start"; ctx.fillText("文字的水平对齐(start)", 300, 230); ctx.direction = "rtl"; ctx.textAlign = "start"; ctx.fillText("文字的水平对齐(start)", 300, 350);
|
textAlign=“end”
当没有设置文字方向ctx.direction
属性或ctx.direction="ltr"
时,其运行效果与ctx.textAlign = "right"
一样;当ctx.direction="rtl"
时,其运行效果与ctx.textAlign = "left"
一样。
1 2 3 4 5
| ctx.textAlign = "end"; ctx.fillText("文字的水平对齐(end)", 300, 280); ctx.direction = "rtl"; ctx.textAlign = "end"; ctx.fillText("文字的水平对齐(end)", 300, 400);
|
这部分的完整代码如下:
{.line-numbers}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "30px Arial, sans-serif";
ctx.textAlign = "left"; ctx.fillText("文字的水平对齐(left)", 300, 60); ctx.textAlign = "center"; ctx.fillText("文字的水平对齐(center)", 300, 110); ctx.textAlign = "right"; ctx.fillText("文字的水平对齐(right)", 300, 160);
ctx.textAlign = "start"; ctx.fillText("文字的水平对齐(start)", 300, 230); ctx.textAlign = "end"; ctx.fillText("文字的水平对齐(end)", 300, 280);
ctx.direction = "rtl"; ctx.textAlign = "start"; ctx.fillText("文字的水平对齐(start)", 300, 350); ctx.textAlign = "end"; ctx.fillText("文字的水平对齐(end)", 300, 400);
ctx.beginPath(); ctx.moveTo(300, 0); ctx.lineTo(300, canvas.height); ctx.moveTo(0, 180); ctx.lineTo(canvas.width, 180); ctx.moveTo(0, 300); ctx.lineTo(canvas.width, 300); ctx.strokeStyle="green"; ctx.stroke();
ctx.font = "16px Arial, sans-serif"; ctx.textAlign="left"; ctx.fillStyle="blue"; ctx.fillText('(ctx.direction = 默认值)', 5, 40); ctx.fillText('(ctx.direction = "ltr")', 5, 200); ctx.fillText('(ctx.direction = "rtl")', 5, 420);
ctx.beginPath(); ctx.arc(300, 60, 4, 0, 2 * Math.PI); ctx.arc(300, 110, 4, 0, 2 * Math.PI); ctx.arc(300, 160, 4, 0, 2 * Math.PI); ctx.arc(300, 210, 4, 0, 2 * Math.PI); ctx.arc(300, 260, 4, 0, 2 * Math.PI); ctx.arc(300, 350, 4, 0, 2 * Math.PI); ctx.arc(300, 400, 4, 0, 2 * Math.PI); ctx.fillStyle = "red"; ctx.fill(); </script>
|
尝试一下 »
3. 垂直对齐
我们先来了解一下六线五格图,如下图所示:
![六线五格图](./image_a2/3-1.png)
六线五格图用于指定一个文本和绘制点之间的关系,除了字母f外其他所有的文字都被限制在该图内,“六线五格”是几乎所有绘图绘制文本的基线图。
Canvas也不例外,Canvas通过设置文字的基线(textBaseline)属性,实现文字的垂直对齐。textBaseline属性包括:
属性 |
说明 |
alphabetic |
默认,文本基线是标准的字母基线 |
top |
文本基线在文本块的顶部 |
hanging |
文本基线是悬挂基线 |
middle |
文本基线在文本块的中间 |
ideographic |
文字基线是表意字基线 |
bottom |
文本基线在文本块的底部 |
基线是指英文(拉丁文)或西亚文字排版中,用于在上面放置字符的一条假想的基准线,而中文和其他东亚文字没有基线。
先看一看运行效果:
![运行效果](./image_a2/3-2.png)
说明:图中的红点为fillText()的坐标点,这里的水平对齐采用的是默认靠左的水平对齐方式。
textBaseline=“alphabetic”(默认值)
文本基线是标准的字母基线,这种方式在英文中比较常见,而中文似乎没多大意义了。注意上图中红点表示的坐标(x,y)位置。
1 2
| ctx.textBaseline = "alphabetic"; ctx.fillText("4 文字垂直对齐(alphabetic, abcdefghijklmnopqrstuvwxyz)", 60, 290);
|
textBaseline=“top”
文本基线在文本块的顶部,这就是我们常说的顶端对齐,在中文中比较好理解,在英文中还需区分hanging的对齐方式。注意上图中红点表示的坐标(x,y)位置。
1 2
| ctx.textBaseline = "top"; ctx.fillText("1 文字垂直对齐(top, abcdefghijklmnopqrstuvwxyz)", 60, 50);
|
textBaseline=“middle”
文本基线在文本块的中间,也就是垂直居中对齐,对于中英文都一样。注意上图中红点表示的坐标(x,y)位置。
1 2
| ctx.textBaseline = "middle"; ctx.fillText("3 文字垂直对齐(middle, abcdefghijklmnopqrstuvwxyz)", 60, 210);
|
textBaseline=“bottom”
文本基线在文本块的底部,这就是我们常说的底端对齐,在中文中比较好理解,在英文中还需区分ideographic的对齐方式。注意上图中红点表示的坐标(x,y)位置。
1 2
| ctx.textBaseline = "bottom"; ctx.fillText("6 文字垂直对齐(bottom, abcdefghijklmnopqrstuvwxyz)", 60, 450);
|
textBaseline=“hanging”
文本基线是悬挂基线
1 2
| ctx.textBaseline = "hanging"; ctx.fillText("2 文字垂直对齐(hanging, abcdefghijklmnopqrstuvwxyz)", 60, 130);
|
textBaseline=“ideographic”
文字基线是表意字基线
1 2
| ctx.textBaseline = "ideographic"; ctx.fillText("5 文字垂直对齐(ideographic, abcdefghijklmnopqrstuvwxyz)", 60, 370);
|
这部分的完整代码如下:
{.line-numbers}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10); ctx.font = "30px sans-serif";
ctx.textBaseline = "top"; ctx.fillText("1 文字垂直对齐(top, abcdefghijklmnopqrstuvwxyz)", 100, 100); ctx.textBaseline = "hanging"; ctx.fillText("2 文字垂直对齐(hanging, abcdefghijklmnopqrstuvwxyz)", 100, 200); ctx.textBaseline = "middle"; ctx.fillText("3 文字垂直对齐(middle, abcdefghijklmnopqrstuvwxyz)", 100, 300); ctx.textBaseline = "alphabetic"; ctx.fillText("4 文字垂直对齐(alphabetic, abcdefghijklmnopqrstuvwxyz)", 100, 400); ctx.textBaseline = "ideographic"; ctx.fillText("5 文字垂直对齐(ideographic, abcdefghijklmnopqrstuvwxyz)", 100, 500); ctx.textBaseline = "bottom"; ctx.fillText("6 文字垂直对齐(bottom, abcdefghijklmnopqrstuvwxyz)", 100, 600);
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(canvas.width, 100); ctx.moveTo(0, 200); ctx.lineTo(canvas.width, 200); ctx.moveTo(0, 300); ctx.lineTo(canvas.width, 300); ctx.moveTo(0, 400); ctx.lineTo(canvas.width, 400); ctx.moveTo(0, 500); ctx.lineTo(canvas.width, 500); ctx.moveTo(0, 600); ctx.lineTo(canvas.width, 600); ctx.strokeStyle="green"; ctx.stroke();
ctx.beginPath(); ctx.arc(100, 100, 4, 0, 2 * Math.PI); ctx.arc(100, 200, 4, 0, 2 * Math.PI); ctx.arc(100, 300, 4, 0, 2 * Math.PI); ctx.arc(100, 400, 4, 0, 2 * Math.PI); ctx.arc(100, 500, 4, 0, 2 * Math.PI); ctx.arc(100, 600, 4, 0, 2 * Math.PI); ctx.fillStyle = "red"; ctx.fill(); </script>
|
尝试一下 »
top与hangling非常相似,ideographic与bottom也一样,这两类在中文的垂直对齐中没有差异,英文(拉丁字母)也只是在某些字体中才会有差异,例如serif字体,请看下图:
![运行效果](./image_a2/3-3.png)
源代码如下:
{.line-numbers}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10); ctx.font = "30px serif";
ctx.textBaseline = "top"; ctx.fillText("(abcdefg)", 50, 50); ctx.textBaseline = "hanging"; ctx.fillText("(abcdefg)", 180, 50); ctx.textBaseline = "middle"; ctx.fillText("(abcdefg)", 310, 50); ctx.textBaseline = "alphabetic"; ctx.fillText("(abcdefg)", 440, 50); ctx.textBaseline = "ideographic"; ctx.fillText("(abcdefg)", 570, 50); ctx.textBaseline = "bottom"; ctx.fillText("(abcdefg)", 700, 50); ctx.font = "16px bold Arial,sans-serif"; ctx.fillStyle="blue"; ctx.fillText("textBaseline: ", 10, 125); ctx.fillText("top", 120, 125); ctx.fillText("hangling", 210, 125); ctx.fillText("middle", 340, 125); ctx.fillText("alphabetic", 450, 125); ctx.fillText("ideographic", 580, 125); ctx.fillText("bottom", 730, 125);
ctx.beginPath(); ctx.moveTo(0, 50); ctx.lineTo(canvas.width, 50); ctx.strokeStyle = "green"; ctx.lineWidth = 2; ctx.stroke(); </script>
|
尝试一下 »
4. 文字间距
设置文字最大宽度
![执行效果](./image_a2/4-1.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "bold 30px Inconsolata"; ctx.textAlign = "left"; ctx.textBaseline = "top"; ctx.fillText("图形系统开发实战: draw text", 60, 60); ctx.fillText("图形系统开发实战: draw text", 60, 130, 300); ctx.fillText("图形系统开发实战: draw text", 60, 200, 200);
ctx.strokeStyle = "red"; ctx.strokeRect(60, 130, 300, 30); ctx.strokeRect(60, 200, 200, 30); </script>
|
尝试一下 »
letterSpacing属性
letterSpacing属性用于设置中文的字与字之间,英文单词的字母与字母之间的距离,其单位为像素(px),其执行效果如下图所示:
![执行效果](./image_a2/4-2.png)
其代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "bold 30px Inconsolata"; ctx.save(); ctx.letterSpacing = "6px"; ctx.fillText("图形系统开发实战: use letterSpacing property", 60, 50); ctx.letterSpacing = "8px"; ctx.fillText("图形系统开发实战: use letterSpacing property", 60, 120); ctx.letterSpacing = "10px"; ctx.fillText("图形系统开发实战: use letterSpacing property", 60, 190); ctx.restore(); </script>
|
尝试一下 »
wordSpacing属性
wordSpacing属性仅对英文有效,该属性可设置单词之间的间距,其执行效果如下图所示:
![执行效果](./image_a2/4-3.png)
其代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "bold 30px Inconsolata"; ctx.save(); ctx.wordSpacing = "10px"; ctx.fillText("图形系统开发实战: use wordSpacing property", 60, 50); ctx.wordSpacing = "20px"; ctx.fillText("图形系统开发实战: use wordSpacing property", 60, 120); ctx.wordSpacing = "30px"; ctx.fillText("图形系统开发实战: use wordSpacing property", 60, 190); ctx.restore(); </script>
|
尝试一下 »
测量文字宽度measureText()
画布渲染上下文提供了测量文字宽度的apimeasureText(text)
,该方法用于在设置font、wordSpacing、letterSpacing等属性后,可测量绘制出来的文本的宽度,其参数为字符串,不仅仅是英文字母、英文单词、英文句子、单个中文和中文句子的宽度都能够测量,使用该api就可以改变文字的坐标,将绘制字符串改变为绘制一个一个的文字,在文字之间增加空白,从而实现改变文字之间间距的目的。
5. 文本垂直排列
英文中由于单词中包含字母数量差异非常大,因此不常采用垂直排布,如果一定需要垂直排布,也是将文字旋转90°或-90°,先看看以下的效果图:
![执行效果](./image_a2/5-1.png)
这种实现方法比较简单,需要注意的是红色的原点为这两行文字的坐标点,在绘制的时候可能需要计算坐标值,画布旋转ctx.rotate()我们将会在后续章节进行讲解,这里暂时略过。其代码如下:
{.line-numbers}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); drawGrid("lightgray", 10, 10);
ctx.font = "30px 黑体"; let text = "使用ctx.rotate()旋转画布, 实现文字垂直排列";
ctx.save(); ctx.translate(50, 50); ctx.rotate(90 * Math.PI / 180); ctx.fillText(text, 0, 0); let textWidth = ctx.measureText(text).width; ctx.restore();
ctx.save(); ctx.translate(150, 50 + textWidth); ctx.rotate(-90 * Math.PI / 180); ctx.fillText(text, 0, 0); ctx.restore();
ctx.beginPath(); ctx.arc(50, 50, 4, 0, 2 * Math.PI); ctx.arc(150, 50 + textWidth, 4, 0, 2 * Math.PI); ctx.fillStyle = "red"; ctx.fill(); </script>
|
尝试一下 »
在这个效果图中,对于英文的垂直排列可能就只有这种方式,但对于中文则可以采取古代书籍的垂直排列方式,如下图所示:
![执行效果](./image_a2/5-2.png)
画布渲染上下文没有提供方法进行这样的垂直排布,我们可以通过一个函数实现这个功能,主要思路如下:
- 逐字(字母/单个中文文字)分析句子中的文字,并逐字记录文字宽度;
- 使用(x,y)作为第一个文字的坐标,同时使用measureText()测量文字宽度,y + 文字宽度 + 文字间隙 作为下一个文字的y坐标;
- 如果是英文字母,按照上述方法把画布旋转90°绘制文字;
- 如果是中文则逐个汉字绘制出来;
上述效果的代码如下:
{.line-numbers}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| <script> let canvas = document.getElementById('canvas'); let ctx = canvas.getContext('2d'); ctx.font = "30px 黑体";
fillTextVertical(ctx, "1.Word文字垂直排列", 50, 60); fillTextVertical(ctx, "2.Word文字垂直排列", 140, 60); </script>
<script>
function fillTextVertical(ctx, text, x, y) { let canvas = ctx.canvas; let arrText = text.split(''); let arrWidth = arrText.map(function (letter) { return ctx.measureText(letter).width; });
ctx.save(); let align = ctx.textAlign; let baseline = ctx.textBaseline;
if (align == 'left' || align == 'start') { x = x + Math.max(...arrWidth) / 2; } else if (align == 'right') { x = x - Math.max(...arrWidth) / 2; } if (baseline == 'bottom' || baseline == 'alphabetic' || baseline == 'ideographic') { y = y - arrWidth[0] / 2; } else if (baseline == 'top' || baseline == 'hanging') { y = y + arrWidth[0] / 2; }
ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
arrText.forEach(function (letter, index) { let code = letter.charCodeAt(0); if (code <= 256) { ctx.translate(x, y); ctx.rotate(90 * Math.PI / 180); ctx.translate(-x, -y); } else if (index > 0 && text.charCodeAt(index - 1) < 256) { y = y + arrWidth[index - 1] / 2; } ctx.fillText(letter, x, y); ctx.setTransform(1, 0, 0, 1, 0, 0); let letterWidth = arrWidth[index]; y = y + letterWidth; }); ctx.restore(); }; </script>
|
尝试一下 »
最后我们在欣赏一篇使用垂直排布绘制的文字效果:
![执行效果](./image_a2/5-3.png)
6. 本章小结
本节讲解在Canvas中绘制文字的方法,包括绘制填充文本、空心文本、设置文本的颜色和字体,设置文本的水平对齐、文本的垂直对齐、文本的间距、文本垂直排列等内容。本节内容使用了Canvas 2D API以下方法:
方法名 |
说明 |
strokeText |
在指定的坐标上绘制文本字符串,并使用当前的strokeStyle进行描边 |
fillText |
在指定的坐标上绘制文本字符串,并使用当前的 fillStyle 对其进行填充 |
measureText |
测量文本宽度等信息 |
属性包括:
属性名 |
说明 |
font |
描述绘制文字时,当前字体样式的属性。使用和 CSS font 规范相同的字符串值。 |
textAlign |
文本的水平对齐方式 |
textBaseline |
文本的垂直对齐方式 |
wordSpacing |
设置单词之间的间距 |
letterSpacing |
设置中文的字与字之间,英文单词的字母与字母之间的距离 |
strokeStyle |
描述画笔(绘制图形)颜色或者样式的属性 |
fillStyle |
描述填充时颜色和样式的属性 |
lineWidth |
设置线段宽度的属性 |
练习一下
(1) 绘制文本
按照以下格式要求在Canvas中绘制你的名字:
- 垂直居中
- 水平居中
- 字体大小:50px
- 字型:黑体
- 颜色:blue
![运行效果](./image_a2/2-exer1.png)
尝试一下 »
(2) 富文本
富文本是指在文字排列时可以指定文字的字体、字型、颜色、粗体、字间距、行间距等信息的文字排布。
上面几个章节讲解了字体的各种绘制效果,已经涵盖到了富文本的各个特性,但每次绘制的都是单个文字或句子,需要我们指定绘制位置(坐标)才能将文字绘制出来。画布渲染上下文有没有提供api可以将一篇文章传入进去,自动换行排布,自动显示文章中各种字体颜色等富文本信息呢?
答案是没有这样的api,这需要我们自己编程序来实现。其解决思路也并不复杂,灵活调用上面这几个api,计算文字所在的位置、设置好字体属性就能实现。
下面是比较常见的一段富文本,由不同颜色的文字组成一了句话,这句话的定义如下,亲爱的读者,动手试一试吧。
1 2 3 4 5 6 7 8 9 10
| [ {"text":"落霞", "color":"red"}, {"text":"与"}, {"text":"孤鹜", "color":"red"}, {"text":"齐飞", wordSpace:60}, {"text":"秋水", "color":"blue"}, {"text":"共"}, {"text":"长天", "color":"blue"}, {"text":"一色"} ];
|
![运行效果](./image_a2/2-exer2.png)
尝试一下 »
本文为“图形开发学院”(www.graphanywhere.com)网站原创文章,遵循CC BY-NC-ND 4.0版权协议,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。
0评论