Canvas学习:绘制文本
前面的课程我们学习的都是如何在Canvas中绘制图形,但很多时候,除了绘制图形之外还有很多情景要同文本打交道。不过在Canvas中到目前为止只提供了一些必备的基本功能,例如文本的描边与填充,向Canvas之中放置文本,以及用像素为单位来计算任意字符串的宽度等。接下来的内容,我们就来了解在Canvas中怎么绘制文本以及一些基本的操作。
Canvas的绘图环境对象提供了两种方法来渲染文本:
fillText(text, x, y, [maxWidth])
:绘制填充文本strokeText(text, x, y, [maxWidth])
:绘制描边文本
在Canvas中同样提供了类似CSS的一些font
属性,用来修饰在Canvas中绘制的文本,比如:
font = value
:用来修饰绘制文本的样式,类似于CSS中的font
textAlign = value
:文本对齐设置textBaseline = value
: 文本基线对齐设置direction = value
: 文本方向的设置
除此之外,很多时候我们还需要对已绘制文本宽度的度量,在Canvas中提供了一个measureText(text)
方法,该方法所返回的对象中,包含一个名为width
的属性,它的值代表你传递给该方法的文本所占据的宽度。
在接下来的内容,我们将详细的针对上述内容做相关的阐述。
文本的填充和描边
在Canvas中的CanvasRenderingContext2D
对象提供了两个方法来绘制文本:fillText()
和strokeText()
方法。先来看fillText()
方法。
fillText()
方法用来绘制填充文本,其语法如下:
ctx.fillText(text, x, y, [maxWidth])
fillText()
方法接受四个参数:
text
:需要绘制的文本内容x
:指定绘制文本在Canvas画布中起始位置的x
轴坐标点y
:指定绘制文本在Canvas画布中起始位置的y
轴坐标点maxWidth
:指定绘制文本的最大宽度
来看个简单的示例:
var text = 'Hello! W3cplus.com !'; // 需要绘制的文本内容
ctx.fillStyle = '#f90'; // 文本颜色
ctx.textAlign = 'center'; // 文本对齐方式
ctx.font = '48px Airal'; // 文本字号、字体
ctx.fillText(text, w / 2, h / 2);
效果如下:
可以点击这里在CodePen上查看Demo效果。
在绘制文本时,同样可以使用fillStyle
属性来设置填充文本的颜色。另外,上面的示例,我们只用了其中三个参数,并没有使用maxWidth
参数。在fillText()
方法中,这个参数是可选参数。这个参数的主要功能是用来控制绘制文本的最大宽度。如果绘制的文本内容超过了maxWidth
的宽度的时候,将会压缩文本,让绘制的文本宽度和maxWidth
值一样。
来个小示例:
var text = 'Hello! W3cplus.com !';
ctx.fillStyle = '#f90';
ctx.textAlign = 'center';
ctx.font = '48px Airal';
ctx.fillText(text, w / 2, h / 2 - 50, 200);
ctx.fillText(text, w / 2, h / 2 + 50);
效果如下:
可以点击这里在CodePen上查看Demo效果。
上示中,绘制的第一个文本,设置了maxWidth
,而第二个文本并未设置maxWidth
。通过ctx.measureText(text).width)
可以得出未设置maxWidth
的值是474
,也就是说文本Hello! W3cplus.com!
从474
压缩到了200
。
上面介绍的是fillText()
绘制填充文本,在Canvas中还可以通过strokeText()
方法来绘制描边文本。该方法具有的参数和使用方法与fillText()
一样,只是最终在Canvas中渲染的效果不一样。比如将上示中的fillText()
换成strokeText()
,同时将fillStyle
换成strokeStyle
:
var text = 'Hello! W3cplus.com !';
ctx.strokeStyle = '#f90';
ctx.textAlign = 'center';
ctx.font = '48px Airal';
ctx.strokeText(text, w / 2, h / 2 - 50, 200);
ctx.strokeText(text, w / 2, h / 2 + 50);
最终效果如下:
可以点击这里在CodePen上查看Demo效果。
在实际中,我们可以同时使用fillText()
和strokeText()
方法绘制一个具有填充的边框的文本,这也是我们最常见的描边文本,但它们的起始位置应该在同一个点:
var text = 'Hello! W3cplus.com !';
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'red';
ctx.lineWidth = 2;
ctx.textAlign = 'center';
ctx.font = '48px Airal';
ctx.fillText(text, w / 2, h / 2);
ctx.strokeText(text, w / 2, h / 2);
最终效果如下:
可以点击这里在CodePen上查看Demo效果。
为了便于更灵活的使用fillText()
和strokeText()
绘制文本,可以将其封装成一个函数,比如drawText()
:
// @param {Object} ctx - CanvasRenderingContext2D
// @param {String} text - 绘制文本的内容
// @param {Number} x - 绘制文本起始点x轴坐标
// @param {Number} y - 绘制文本起始点y轴坐标
// @param {Boolean} isFill - 是否填充,true绘制填充文本,false绘制描边文本
// @param {Boolean} isMaxWidth - 是否设置文本最大宽度, true设置最大宽度, false不设置最大宽度
// @param {String} color - 绘制文本颜色
// @param {Number} maxWidth - 文本最大宽度
function drawText(ctx, text, x, y, isFill, isMaxWidth, color, maxWidth) {
if (isFill) {
ctx.fillStyle = color;
if (isMaxWidth) {
ctx.fillText(text, x, y, maxWidth);
} else {
ctx.fillText(text, x, y);
}
} else {
ctx.strokeStyle = color;
if (isMaxWidth) {
ctx.strokeText(text, x, y, maxWidth);
} else {
ctx.strokeText(text, x, y);
}
}
}
使用的时候,像下面这样调用即可:
drawText(ctx, 'W3cplus.com', w / 2, 40, true, false, 'blue');
drawText(ctx, 'W3cplus.com', w / 2, 80, true, true, 'blue', 100);
设置文本样式
在上面的示例中,我们看到了代码中有ctx.font
属性的使用。其实在Canvas中,可以通过绘图环境对象的font
属性,来设置绘制在Canvas之中的文本所采用的字型。该属性是一个CSS3格式的字型字符串,它和CSS font
属性相同的语法,默认的字型是10px sans-serif
。
Canvas中font
属性的各个分量如下表所示:
字型属性分量 | 描述 |
---|---|
font-style |
可以取如下三个值:normal 、italic 和oblique |
font-variant |
可以取这两个值:normal 和small-caps |
font-weight |
决定该字型的字符笔画粗细,可取如下值:normal 、lighter 、bold 和bolder ,也可以采用对应的数值,比如normal 对应的是400 |
font-size |
字型的大小,可以使用关键词xx-small 、x-small 、small 、medium 、large 、x-large 、xx-large 、smaller 、larger ;也可以使用具体的带有长度单位的数值,比如20px |
line-height |
浏览器会将该属性强制设置为其默认值normal ,如果你设置了该值,浏览器会忽略你所设定的值 |
font-family |
设置字体 |
**通过CSS3与Canvas来指定字型属性时的区别:**绘制环境对象的
font
属性也支持CSS3格式的字型语法,除了样式语法所特有的属性,例如inherit
或initial
等。如果你不巧刚好用到了inherit
或initial
的话,那么浏览器在执行到那行代码时会悄然地失败,并不抛出任何异常,同时也不会将该值设定给font
属性。通过Canvas来设置字型属性与通过CSS3来设置相比,还有一个区别:在Canvas中设置line-height
属性时,浏览器将忽略其值,因为规范要求浏览器必须将该值设置为normal
。
文本定位(对齐方式)
这里所说的文本定位,其实指的是对齐方式,在CSS中我们可以使用text-align
设置文本水平对齐方式,vertical-align
设置文本垂直方向的对齐方式。在Canvas中也有对应的属性。
通过前面的知识我们得知,在Canvas中使用fillText()
或strokeText()
绘制文本时,需要指定所绘文本的x
与y
坐标,然而,浏览器具体会将文本绘制在何处(文本定位),则要看textAlign
与textBaseline
这两个绘图环境对象的属性。
textAlign
**CanvasRenderingContext2D.textAlign
**是Canvas中绘制文本时文本的对齐方式的属性。其对齐是基于fillText()
或strokeText()
方法的x
值。textAlign
属性有点类似于CSS中的text-align
,用来设置文本水平对齐方式。其主要包括:
ctx.textAlign = "left" || "right" || "center" || "start" || "end";
left
:文本左对齐right
:文本右对齐center
:文本居中对齐start
:文本对齐界线开始的地方(左对齐指本地从左向右,右对齐指本地从右向左)end
:文本对齐界线结束的地方(左对齐指本地从左向右,右对齐指本地从右向左)
默认值是start
。在Canvas中使用textAlign
时同样会受direction
属性值的影响。当Canvas的direction
的值为ltr
时,也就是说浏览器是按照由左至右的方向来显示文本时,textAlign
的left
的效果与start
相同,而right
的效果则与end
相同。同理,如果direction
的值为rtl
时,也就是说浏览器是从右至左来显示文本的,那么textAlign
的right
的效果则与start
一致,而left
则与end
一致。下例演示了textAlign
每个值在浏览器中渲染的效果(其中direction
的值为默认值ltr
):
var text = ['left', 'right', 'center', 'start', 'end'];
ctx.fillStyle = '#f36';
ctx.font = '32px Airal';
for (var i = 0; i < text.length; i++) {
ctx.textAlign = text[i];
ctx.fillText('textAlign:' + text[i], w / 2, (i + 1) * 50);
}
效果如下:
可以点击这里在CodePen上查看Demo效果。
示例中绘制的文本,其起始点是画布的中心位置w / 2
,也就是上图中的黑色竖线。left
则让文本左侧在x
点处(在竖线右侧),right
则文本右侧在x
点处(在竖线左侧),center
则文本中间点在x
点处(在竖线中间)。start
和left
等同,end
和right
等同。
这里的
textAlign='center'
比较特殊。textAlign
的值为center
时候文本的居中是基于你在fillText
的时候所给的x
的值,也就是说文本一半在x
的左边,一半在x
的右边(上图展示看得更清楚些)。所以,如果你想让文本在整个Canvas居中,就需要将fillText
的x
值设置成canvas
的宽度的一半。
textBaseline
CanvasRenderingContext2D.textBaseline
是Canvas中描述绘制文本时,当前文本基线的属性,类似CSS中的vertical-align
属性,在介绍textBaseline
属性之前,先来下图,下图展示了textBaseline
属性支持的不同的基线情况:
上图是不是非常熟悉呀,那我们回到Canvas的textBaseline
属性的使用:
ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";
top
:文本基线在文本块的顶部hanging
:文本基线是悬挂基线middle
:文本基线在文本块的中间alphabetic
:文本基线是标准的字母基线ideographic
:文字基线是表意字基线,如果字符本身超出了alphabetic
基线,那么ideograhpic
基线位置在字符本身的底部bottom
:文本基线在文本块的底部,与ideographic
基线的区别在于ideographic
基线不需要考虑下行字母
textBaseline
的默认值是alphabetic
,该值用于绘制由基于拉丁字母的语言所组成的字符串,ideographic
值则用于绘制日文或中文字符串,hanging
值用于绘制各种印度语字符串,top
、bottom
和middle
这三个值与特定的语言不相关,它们代表文本周围的边界框之内的某个位置,这个边界框也叫做“字符方框”。
同样来看一个示例,用效果来帮助我们理解textBaseline
各个值的效果。
var text = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'];
ctx.fillStyle = '#f36';
ctx.font = '24px Airal';
for (var i = 0; i < text.length; i++) {
ctx.textBaseline = text[i];
ctx.fillText(text[i], (i + 1) * 150, h / 2);
}
效果如下:
可以点击这里在CodePen上查看Demo效果。
文本度量
只要你做的事情与文本有关,你就得设法获取某个字符串的像素宽度和高度。在Canvas中提供了measureText()
方法,这个方法返回一个TextMetrics
对象,这个对象中包含了一个名为width
的属性,这个属性就是字符串的宽度。
var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;
在使用measureText()
方法时,常见的错误就是在调用完该方法之后,才去设置字型。请注意:measureText()
方法是根据当前的字型来计算字符串宽度的,因此,如果你在调用measureText()
方法之后才去改变字型,那么该方法所返回的宽度并不能反映出以那种字型来度量的实际文本宽度。
上述的内容就是有关于Canvas中绘制文本所涉及到的一些方法和属性。接下来我们来看两个简单的示例。
示例
前面的示例,我们看到的是通过fillText()
或strokeText()
方法绘制填充文本或描边文本,可以说是最简单的绘制文本效果,但实际当中,我们要的效果不仅仅是这些普通的效果。比如我们需要一个圆形的文本效果,3D的文本效果等。那咱们就借助以前所学的一些基础知识来实现这两种效果。
环形文本
直接上代码,这里封装了一个简单的函数,比如drawCircleText()
,并且根据绘制弧形文本所需要的参数传给这个函数,具体代码如下:
// @param {Object} ctx - CanvasRenderingContext2D
// @param {String} text - 需要绘制制的文本
// @param {Number} x - 绘制文本起始点x轴坐标点
// @param {Number} y - 绘制文本起始点y轴坐标点
// @param {Number} radius - 圆形半径, 弧度值
// @param {Number} startAngle - 开始的角度值
// @param {Boolean} isFill - 是否填充,true填充,false描边
// @param {String} color - 文本颜色
function drawCircleText(ctx, text, x, y, radius, startAngle, isFill, color) {
// 将startAngle角度转换成弧度
var startRad = Math.PI * startAngle / 180;
// 所绘文本的长度
var len = text.length;
// 每个字符所对应的弧度
var numRadsPerLetter = Math.PI * 2 / len;
ctx.save();
// 将坐标原点移到(x, y)
ctx.translate(x, y);
// 将坐标旋转startRad
ctx.rotate(startRad);
// 对字符做操作
for (var i = 0; i < len; i++) {
ctx.save();
// 每个字符旋转
ctx.rotate(i * numRadsPerLetter);
// isFill为true填充, false为描边
if (isFill) {
ctx.fillStyle = color;
ctx.fillText(text[i], 0, -radius);
} else {
ctx.strokeStyle = color;
ctx.strokeText(text[i], 0, -radius);
}
ctx.restore();
}
ctx.restore();
}
在使用的时候,只需要调用这个函数,并传入相应的值:
ctx.font = 'bold 40px Arial';
drawCircleText(ctx, 'W3CPLUC.COM!', w / 2, h / 2, 100, 0, true, 'orange');
效果如下:
3D文本效果
3D文本效果在CSS中通过text-shadow
来实现,具体怎么实现这里就不多说了,必竟我们这里是聊Canvas。其实在Canvas中实现的原理也有点类似,将会使用到shadowBluer
、shadowColor
等阴影属性(这个我们前面没有接触过,但后面我们也会深入学习),和前面的圆形文本一样,同样将绘制3D文本的效果封装成一个简单的函数,比如draw3DText()
,具体的代码如下:
// @param {Object} ctx - CanvasRenderingContext2D
// @param {String} text - 绘制的文本内容
// @param {Number} x - 文本起始点x轴坐标
// @param {Number} y - 文本起始点y轴坐标
// @param {Number} textDepth - 阴影的深度
// @param {Boolean} isFill - 文本是否填充,true为填充,false为描边
// @param {String} color - 文本颜色
// @param {String} shadowColor - 阴影颜色
// @param {Number} shadowBlur - 阴影距离
// @param {Number} interval - 间距
function draw3DText(ctx, text, x, y, textDepth,isFill, color, shadowColor, shadowBlur, interval) {
var i;
for (i = 0; i < textDepth; i++) {
if(isFill) {
ctx.fillText(text, x - i, y - i);
} else {
ctx.strokeText(text, x - i, y - i);
}
}
ctx.shadowColor = shadowColor;
ctx.shadowBlur = shadowBlur;
ctx.shadowOffsetX = textDepth + interval;
ctx.shadowOffsetY = textDepth + interval;
if (isFill) {
ctx.fillStyle = color;
ctx.fillText(text, x - i, y - i);
} else {
ctx.strokeStyle = color;
ctx.strokeText(text, x - i, y - i);
}
}
调用也非常的简单:
ctx.font = '60px Verdana';
ctx.textAlign = 'center';
ctx.textBaseline= 'middle';
draw3DText(ctx, 'W3cplus', w / 2, h / 2, 6, true, '#0094ed', '#000', 12, 2);
得到的效果如下:
这个示例通过将fillText()
或者strokeText()
的(x, y)
设置为canvas
宽度和高度的一半(w / 2, h / 2)
再配合ctx.textAlign = 'center'
和ctx.textBaseline= 'middle'
可以实现所绘文本在画布的中间,也就是实现了我们常说的水平垂直居中的效果。
另外,把上面两外效果结合起来,就可以实现圆形的3D文本效果,要是再添加一点动画功能,效果就不一样了:
总结
这篇文章我们主要介绍了在Canvas中绘制文本的一些基础知识,在Canvas中可以通过ctx.fillText()
绘制填充文本,ctx.strokeText()
可以绘制描边文本,另外通过ctx.textAlign
和ctx.textBaseline
设置所绘制文本的位置,并且使用ctx.measureText('text').width
可以得到所绘制文本text
的宽度值,虽然这个值并不精确,但在Canvas中有方法可以解决,至于怎么解决我们后续的内容将会介绍。
虽然这些功能是绘制文本的基本功能,但结合Canvas其他的功能,我们可以绘制出很多不同的文本效果,至于绘制出什么样的效果,则需要大家去思考,因为创意是自己的,有了创意,然后结合自己所掌握的Canvas知识,能做的事情就更多了。如果你有更好的创意,希望在下面的评论中与我们一起分享。
如需转载,烦请注明出处:https://www.fedev.cn/canvas/drawing-text.htmlnike air max 90 amazon