在Canvas画布上如何实现按中文古典方式垂直排列?

运行效果

按中文古典方式垂直排列,如上图,对于英文可将英文字符从上至下逐个绘制,并通过刚刚讲述的文字旋转方式实现文本垂直排列,但对于中文则可以采取中文古典的垂直排列方式,中文古典的垂直排列方式是通过将汉字从上至下逐字绘制出来。
这种文本垂直排列的实现思路是:首先,对句子中的每个字符(单词或单个中文文字)进行逐字分析,可通过js内部的的charCodeAt()方法判断为英文字母或中文文字,并使用measureText()方法测量每个字符的宽度;然后根据这些宽度信息,逐字计算每个文字的坐标。

通常,我们将(x,y)作为第一个文字的坐标,对于后续的文字,x坐标保持不变,而y坐标则为前一个文字的y坐标加上该文字的宽度以及预设的文字间隙。以此类推,我们可以计算出每个文字的xy坐标。接下来,如果是英文字母,我们需要将画布旋转90°,然后绘制文字;而对于中文,则逐个汉字进行绘制。

以下是一个网页示例,展示了如何在Canvas上按文字旋转方式垂直排列:

示例效果与源代码:

运行效果

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<!DOCTYPE html>
<html lang="zh_CN">

<head>
<title>绘制基本图形(文本垂直排列)</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="图形系统开发实战:基础篇 示例">
<meta name="author" content="hjq">
<meta name="keywords" content="canvas,anygraph,javascript,图形">
</head>

<body style="margin:10px;">
<canvas id="canvas" width="1100" height="260" style="border:solid 1px #CCCCCC; box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.5);" />
</body>
<script>
// 从页面中获取画板对象
let canvas = document.getElementById('canvas');
// 从画板中获取“2D渲染上下文”对象
let ctx = canvas.getContext('2d');

// 开始绘制文本
let x = 21 * 50;

ctx.font = "30px 黑体";
fillTextVertical(ctx, "水调歌头 苏轼", x - (1*50) + 20, 60);

ctx.font = "30px 楷体";
fillTextVertical(ctx, "明月几时有", x - (2*50), 60);
fillTextVertical(ctx, "把酒问青天", x - (3*50), 60);
fillTextVertical(ctx, "不知天上宫阙", x - (4*50), 60);
fillTextVertical(ctx, "今夕是何年", x - (5*50), 60);
fillTextVertical(ctx, "我欲乘风归去", x - (6*50), 60);
fillTextVertical(ctx, "又恐琼楼玉宇", x - (7*50), 60);
fillTextVertical(ctx, "高处不胜寒", x - (8*50), 60);
fillTextVertical(ctx, "起舞弄清影", x - (9*50), 60);
fillTextVertical(ctx, "何似在人间", x - (10*50), 60);

fillTextVertical(ctx, "转朱阁", x - (11*50), 60);
fillTextVertical(ctx, "低绮户", x - (12*50), 60);

fillTextVertical(ctx, "照无眠", x - (13*50), 60);
fillTextVertical(ctx, "不应有恨", x - (14*50), 60);
fillTextVertical(ctx, "何事长向别时圆", x - (15*50), 60);
fillTextVertical(ctx, "人有悲欢离合", x - (16*50), 60);
fillTextVertical(ctx, "月有阴晴圆缺", x - (17*50), 60);
fillTextVertical(ctx, "此事古难全", x - (18*50), 60);

ctx.fillStyle="red";
fillTextVertical(ctx, "但愿人长久", x - (19*50), 60);
fillTextVertical(ctx, "千里共婵娟", x - (20*50), 60);
ctx.fillStyle="black";


// 垂直排布文字
function fillTextVertical(ctx, text, x, y) {
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>

</html>

在这个示例中,我们首先定义了一个Canvas元素,并设置了其宽度和高度。然后,通过JavaScript中canvas.getContext()方法获取从画板中获取“2D渲染上下文”对象。
接下来通过文字旋转,实现文字垂直排列效果。
首先自定义一个fillTextVertical()函数,该函数用于绘制垂直排列的文字。在fillTextVertical()函数中,首先,使用measureText()方法,测量每个文字的宽度并记录。然后,根据这些宽度信息,计算每个文字的x坐标和y坐标;如果文字为英文字符,则是用rotate()方法将画布旋转90度。而对于中文则逐个汉字进行绘制。最终,绘制出垂直排列的文字。显示出这种效果。