持续创作,加速成长!这是我参与「日新计划 6 月更文挑战」的第7天,点击查看活动详情
介绍
或许你时不时会用纯画布来完成一些简单的绘制任务,但是很多小伙伴经常遇到在canvas的文字它不自动换行,就有些烦躁,不要怕,本期就用短短几行的代码来让你canvas的文字多行显示,而且兼容性也是非常不错的,还等什么,我们这就是出发~
正文
在完成多行文本之前,我们先来写一个普通文本绘制到画布上的示例:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
createCard();
function createCard(w = width, h = height) {
let gradient = ctx.createLinearGradient(0, h, w, 0);
gradient.addColorStop(0, '#8A88FB');
gradient.addColorStop(1, '#D079EE');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, w, h);
let text = "春有百花秋有月,夏有凉风冬有雪。莫将闲事挂心头,便是人间好时节。";
drawText(text,10,100)
}
function drawText(text,x = 0, y = 0) {
ctx.font = window.getComputedStyle(canvas).font;
ctx.fillStyle = 'white'
ctx.textAlign = "start"
ctx.textBaseline = "top"
ctx.fillText(text, x, y);
}
你可以发现这是一段比较长的文本,如果直接绘制到画布上,那么多出来的部分则会不显示。那么如何让其自动让其在一个指定宽度下换行呢?且看我们后面对它的改造。
在改成多行之前,先分析一下,其实最关键的是用到了 CanvasRenderingContext2D.measureText()
这个方法,它会返回一个关于被测文本 TextMetrics
的对象信息,TextMetrics
里面的信息都是只读的,其中我们就用到了它里面的 width
即,该文本的宽度 。我们将会逐字进行遍历,不断叠加字符串来判断这个字符串是否超过了所需的最大限宽,如果到达了减到一个字符再保存这一段字符串,然后再继续下一段的获取。周而复始,我们将会得到一个段落的数组,最后再遍历绘制这数组里的文本段落就可以实现换行操作啦。
function getWrapText(text = "", maxWidth = 200) {
let txtList = [];
let str = "";
for (let i = 0, len = text.length; i < len; i++) {
str += text.charAt(i);
if (ctx.measureText(str).width > maxWidth) {
txtList.push(str.substring(0, str.length - 1))
str = ""
i--
}
}
txtList.push(str)
return txtList;
}
我们先写一个 getWrapText
方法来获取文本拆分后的数组,这里唯一要注意的是如果大于宽度要减去一个字符,此时 i
需要减去1的,表示从被减去的那个序列为下一段的开始。
然后,我们还要改写一下 drawText
方法:
function drawText(text, x = 0, y = 0, lineHeight = 60, maxWidth = 200) {
ctx.font = window.getComputedStyle(canvas).font;
ctx.fillStyle = 'white'
ctx.textAlign = "start"
ctx.textBaseline = "top"
getWrapText(text, maxWidth).forEach((txt, index) => {
ctx.fillText(txt, x, y + lineHeight * index);
})
}
这里我们加入了 lineHeight
表示行高, maxWidth
表示最大限宽。最后我们通过 forEach
遍历去绘制每段的文本,就会发现这个文本已经满足多行显示的要求了~
演示
https://code./pen/7113749958565560350