图形系统开发实战课程:基础篇——2.绘制文字


在这里插入图片描述

图形开发学院|GraphAnyWhere

第二章:绘制文字

本章的内容包括:

  • 绘制常见的文本
  • 文本的水平对齐
  • 文本的垂直对齐
  • 文本的间距
  • 文本垂直排列
  • 富文本

1. 绘制常见的文本

画布渲染上下文提供了两个api用于绘制文本:

ctx.strokeText(text, x, y[, maxWidth]);
ctx.fillText(text, x, y[, maxWidth]);

\quad strokeText()是用于绘制文本外框,而fillText()是填充文本。我们先看一下绘制结果:

在这里插入图片描述

绘制填充文字

\quad 我们日常见到的文字就是填充的文字,通过fillText()方法,就能够直接在画布中绘制填充的文字。其代码为:

ctx.font = "40px 黑体";
ctx.fillText("绘制普通中文和English文字", 50, 80);

\quad Canvas通过font属性指定字体大小和字体名称,其格式和css样式中用法的一致,这里的文字大小通常指的就是文字的高度,其单位为像素(px)。

绘制空心文字

\quad 在画布中绘制空心文字也很简单,只需通过strokeText()方法即可实现,其代码如下:

ctx.font = "40px 黑体";
ctx.strokeText("绘制空心中文和English文字", 50, 150);

绘制空心文字还可以通过线宽lineWidth属性指定边框的大小,其效果如下图所示:
在这里插入图片描述

源代码如下:

// 绘制文字边框
ctx.font = "40px 黑体";
ctx.lineWidth = 1;
ctx.strokeText("边框粗细", 60, 60);
ctx.lineWidth = 2;
ctx.strokeText("边框粗细", 260, 60);
ctx.lineWidth = 3;
ctx.strokeText("边框粗细", 460, 60);

指定字体的其他样式

\quad 渲染上下文对象还提供了一些属性可以设置字体、字号、粗体、斜体、文字颜色等样式。

属性名称说明
ctx.font设置字体属性,包括字体、字号、粗细、斜体等样式
ctx.fillStyle设置字体颜色
ctx.strokeStyle设置在绘制空心文字时边框的大小

下面这个示例设置几种字体和字号,并设置了粗体和斜体,其效果如下图所示:

在这里插入图片描述

源代码如下:

<script>
    // 从页面中获取画板对象
    let canvas = document.getElementById('canvas');
    // 从画板中获取“2D渲染上下文”对象
    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 仿宋"

绘制带阴影的文字

\quad 画布渲染上下文直接提供了shadowColorshadBlur等属性,可实现绘制带阴影的文字,这几个属性的说明如下:

属性说明
shadowBlur模糊效果程度
shadowColor阴影颜色
shadowOffsetX阴影水平偏移距离,默认值是 0。
shadowOffsetY阴影垂直偏移距离,默认值是 0。

下面这个示例绘制了几个带阴影的文字,其效果如下图所示:

在这里插入图片描述

源代码如下:

<script>
    // 从页面中获取画板对象
    let canvas = document.getElementById('canvas');
    // 从画板中获取“2D渲染上下文”对象
    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>

绘制带背景的文字

\quad 带背景的文字其实是绘制了一次空心文字和一次填充文字,且在绘制空心文字时需要将线宽指定大一点,其代码如下:

ctx.font = "22px 黑体";
ctx.lineWidth = 5;
ctx.strokeStyle = "#CCCCCC";
ctx.strokeText("带背景的文字", 100, 310);
ctx.fillStyle="#000000";
ctx.fillText("带背景的文字", 100, 310);

\quad 带背景的文字通常应用在背景比较复杂的图形中,例如地理图或包含了多种颜色的图像,这类图形有可能是浅色背景,也有可能是深色背景,给文字添加了背景后,就能够直观突出文字了,如下图中的滤镜名称就应用了这种文字效果。

在这里插入图片描述


2. 水平对齐

\quad 在office word中排版时,我们经常会用到文字水平对齐功能,Canvas也提供了类似的功能(其实word本质上也是一个使用绘图功能开发出来的应用软件)。画布渲染上下文提供了textAlign属性,可指定文字的水平对齐方式,该属性可选择以下几个值:

属性说明
left文本左对齐
right文本右对齐
center文本居中对齐
start默认值,文本对齐界线开始的地方(左对齐指本地从左向右,右对齐指本地从右向左)
end文本对齐界线结束的地方(左对齐指本地从左向右,右对齐指本地从右向左)

我们看一下各种水平对齐方式的运行效果,如下图所示:

在这里插入图片描述

textAlign=“left”

\quad 文本左对齐比较好理解,指的是在水平方向从给定的x坐标值开始,将文字字符串从左向右延伸排列。注意上图中红点表示的坐标(x,y)位置。

// 绘制各种水平对齐的文本
ctx.textAlign = "left";
ctx.fillText("文字的水平对齐(left)", 300, 60);

textAlign=“center”

\quad 文本居中对齐指的是在水平方向从给定的x坐标值开始,将文字字符串居中向两端排列(也就是说文本一半在x的左边,一半在x的右边)。注意上图中红点表示的坐标(x,y)位置。

// 绘制各种水平对齐的文本
ctx.textAlign = "center";
ctx.fillText("文字的水平对齐(center)", 300, 110);

textAlign=“right”

\quad 文本右对齐指的是在水平方向从给定的x坐标值开始,将文字字符串从右向左延伸排列。注意上图中红点表示的坐标(x,y)位置。

// 绘制各种水平对齐的文本
ctx.textAlign = "right";
ctx.fillText("文字的水平对齐(right)", 300, 160);

textAlign=“start”

\quad 该值为默认缺省值,当没有设置文字方向ctx.direction属性或ctx.direction="ltr"时,其运行效果与ctx.textAlign = "left"一样;当ctx.direction="rtl"时,其运行效果与ctx.textAlign = "right"一样。

// 绘制各种水平对齐的文本
ctx.textAlign = "start";
ctx.fillText("文字的水平对齐(start)", 300, 230);
ctx.direction = "rtl";
ctx.textAlign = "start";
ctx.fillText("文字的水平对齐(start)", 300, 350);

textAlign=“end”

\quad 当没有设置文字方向ctx.direction属性或ctx.direction="ltr"时,其运行效果与ctx.textAlign = "right"一样;当ctx.direction="rtl"时,其运行效果与ctx.textAlign = "left"一样。

ctx.textAlign = "end";
ctx.fillText("文字的水平对齐(end)", 300, 280);
ctx.direction = "rtl";
ctx.textAlign = "end";
ctx.fillText("文字的水平对齐(end)", 300, 400);

这部分的完整代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    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. 垂直对齐

我们先来了解一下六线五格图,如下图所示:
在这里插入图片描述

\quad 六线五格图用于指定一个文本和绘制点之间的关系,除了字母f外其他所有的文字都被限制在该图内,“六线五格”是几乎所有绘图绘制文本的基线图。
\quad Canvas也不例外,Canvas通过设置文字的基线(textBaseline)属性,实现文字的垂直对齐。textBaseline属性包括:

属性说明
alphabetic默认,文本基线是标准的字母基线
top文本基线在文本块的顶部
hanging文本基线是悬挂基线
middle文本基线在文本块的中间
ideographic文字基线是表意字基线
bottom文本基线在文本块的底部

基线是指英文(拉丁文)或西亚文字排版中,用于在上面放置字符的一条假想的基准线,而中文和其他东亚文字没有基线。

先看一看运行效果:
在这里插入图片描述

说明:图中的红点为fillText()的坐标点,这里的水平对齐采用的是默认靠左的水平对齐方式。

textBaseline=“alphabetic”(默认值)

\quad 文本基线是标准的字母基线,这种方式在英文中比较常见,而中文似乎没多大意义了。注意上图中红点表示的坐标(x,y)位置。

ctx.textBaseline = "alphabetic";
ctx.fillText("4 文字垂直对齐(alphabetic, abcdefghijklmnopqrstuvwxyz)", 60, 290);

textBaseline=“top”

\quad 文本基线在文本块的顶部,这就是我们常说的顶端对齐,在中文中比较好理解,在英文中还需区分hanging的对齐方式。注意上图中红点表示的坐标(x,y)位置。

ctx.textBaseline = "top";
ctx.fillText("1 文字垂直对齐(top, abcdefghijklmnopqrstuvwxyz)", 60, 50);

textBaseline=“middle”

\quad 文本基线在文本块的中间,也就是垂直居中对齐,对于中英文都一样。注意上图中红点表示的坐标(x,y)位置。

ctx.textBaseline = "middle";
ctx.fillText("3 文字垂直对齐(middle, abcdefghijklmnopqrstuvwxyz)", 60, 210);

textBaseline=“bottom”

\quad 文本基线在文本块的底部,这就是我们常说的底端对齐,在中文中比较好理解,在英文中还需区分ideographic的对齐方式。注意上图中红点表示的坐标(x,y)位置。

ctx.textBaseline = "bottom";
ctx.fillText("6 文字垂直对齐(bottom, abcdefghijklmnopqrstuvwxyz)", 60, 450);

textBaseline=“hanging”

\quad 文本基线是悬挂基线

ctx.textBaseline = "hanging";
ctx.fillText("2 文字垂直对齐(hanging, abcdefghijklmnopqrstuvwxyz)", 60, 130);

textBaseline=“ideographic”

\quad 文字基线是表意字基线

ctx.textBaseline = "ideographic";
ctx.fillText("5 文字垂直对齐(ideographic, abcdefghijklmnopqrstuvwxyz)", 60, 370);

这部分的完整代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    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>

\quad top与hangling非常相似,ideographic与bottom也一样,这两类在中文的垂直对齐中没有差异,英文(拉丁字母)也只是在某些字体中才会有差异,例如serif字体,请看下图:
在这里插入图片描述

源代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    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. 文字间距

设置文字最大宽度

在这里插入图片描述

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    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属性

\quad letterSpacing属性用于设置中文的字与字之间,英文单词的字母与字母之间的距离,其单位为像素(px),其执行效果如下图所示:
在这里插入图片描述

其代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    drawGrid("lightgray", 10, 10);

    // 设置字体属性
    ctx.font = "bold 30px Inconsolata";
    
    // 修改letterSpacing属性绘制文本
    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属性

\quad wordSpacing属性仅对英文有效,该属性可设置单词之间的间距,其执行效果如下图所示:
在这里插入图片描述

其代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    drawGrid("lightgray", 10, 10);

    // 设置字体属性
    ctx.font = "bold 30px Inconsolata";
    
    // 修改wordSpacing属性绘制文本
    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()

\quad 画布渲染上下文提供了测量文字宽度的apimeasureText(text),该方法用于在设置font、wordSpacing、letterSpacing等属性后,可测量绘制出来的文本的宽度,其参数为字符串,不仅仅是英文字母、英文单词、英文句子、单个中文和中文句子的宽度都能够测量,使用该api就可以改变文字的坐标,将绘制字符串改变为绘制一个一个的文字,在文字之间增加空白,从而实现改变文字之间间距的目的。


5. 文本垂直排列

\quad 英文中由于单词中包含字母数量差异非常大,因此不常采用垂直排布,如果一定需要垂直排布,也是将文字旋转90°或-90°,先看看以下的效果图:

在这里插入图片描述

\quad 这种实现方法比较简单,需要注意的是红色的原点为这两行文字的坐标点,在绘制的时候可能需要计算坐标值,画布旋转ctx.rotate()我们将会在后续章节进行讲解,这里暂时略过。其代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // drawGrid
    drawGrid("lightgray", 10, 10);

    // 设置字体属性
    ctx.font = "30px 黑体";
    let text = "使用ctx.rotate()旋转画布, 实现文字垂直排列";

    // 绘制文本1
    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();

    // 绘制文本2
    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>

\quad 在这个效果图中,对于英文的垂直排列可能就只有这种方式,但对于中文则可以采取古代书籍的垂直排列方式,如下图所示:

在这里插入图片描述

\quad 画布渲染上下文没有提供方法进行这样的垂直排布,我们可以通过一个函数实现这个功能,主要思路如下:

  • 逐字(字母/单个中文文字)分析句子中的文字,并逐字记录文字宽度;
  • 使用(x,y)作为第一个文字的坐标,同时使用measureText()测量文字宽度,y + 文字宽度 + 文字间隙 作为下一个文字的y坐标;
  • 如果是英文字母,按照上述方法把画布旋转90°绘制文字;
  • 如果是中文则逐个汉字绘制出来;

上述效果的代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    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) {
            // 英文字符,旋转90°
            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 = y + arrWidth[index - 1] / 2;
        }
        ctx.fillText(letter, x, y);
        // 旋转坐标系还原成初始态
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        // 确定下一个字符的y坐标位置
        let letterWidth = arrWidth[index];
        y = y + letterWidth;
    });
    ctx.restore();
};
</script>

最后我们在欣赏一篇使用垂直排布绘制的文字效果:

在这里插入图片描述


6. 本章小结

\quad 本节讲解在Canvas中绘制文字的方法,包括绘制填充文本、空心文本、设置文本的颜色和字体,设置文本的水平对齐、文本的垂直对齐、文本的间距、文本垂直排列等内容。本节内容使用了Canvas 2D API以下方法:

方法名说明
strokeText在指定的坐标上绘制文本字符串,并使用当前的strokeStyle进行描边
fillText在指定的坐标上绘制文本字符串,并使用当前的 fillStyle 对其进行填充
measureText测量文本宽度等信息

属性包括:

属性名说明
font描述绘制文字时,当前字体样式的属性。使用和 CSS font 规范相同的字符串值。
textAlign文本的水平对齐方式
textBaseline文本的垂直对齐方式
wordSpacing设置单词之间的间距
letterSpacing设置中文的字与字之间,英文单词的字母与字母之间的距离
strokeStyle描述画笔(绘制图形)颜色或者样式的属性
fillStyle描述填充时颜色和样式的属性
lineWidth设置线段宽度的属性

练习一下

(1) 绘制文本

按照以下格式要求在Canvas中绘制你的名字:

  • 垂直居中
  • 水平居中
  • 字体大小:50px
  • 字型:黑体
  • 颜色:blue

在这里插入图片描述

(2) 富文本

\quad 富文本是指在文字排列时可以指定文字的字体、字型、颜色、粗体、字间距、行间距等信息的文字排布。

\quad 上面几个章节讲解了字体的各种绘制效果,已经涵盖到了富文本的各个特性,但每次绘制的都是单个文字或句子,需要我们指定绘制位置(坐标)才能将文字绘制出来。画布渲染上下文有没有提供api可以将一篇文章传入进去,自动换行排布,自动显示文章中各种字体颜色等富文本信息呢?

\quad 答案是没有这样的api,这需要我们自己编程序来实现。其解决思路也并不复杂,灵活调用上面这几个api,计算文字所在的位置、设置好字体属性就能实现。

\quad 下面是比较常见的一段富文本,由不同颜色的文字组成一了句话,这句话的定义如下,亲爱的读者,动手试一试吧。

[
    {"text":"落霞", "color":"red"},
    {"text":"与"},
    {"text":"孤鹜", "color":"red"},
    {"text":"齐飞", wordSpace:60},
    {"text":"秋水", "color":"blue"},
    {"text":"共"},
    {"text":"长天", "color":"blue"},
    {"text":"一色"}
];

在这里插入图片描述

相关资料

系列教程及代码资料:https://GraphAnyWhere.com
图形系统开发实战课程:基础篇——图形系统概述
图形系统开发实战课程:基础篇——1.绘制基本图形


作者信息

作者 : 图形开发学院
CSDN: https://blog.csdn.net/2301_81340430?type=blog
官网:https://graphanywhere.com

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值