初识canvas(二)
上节文章中,给大家分享了canvas
最基础的用法,包括绘制线条、控制渲染方式、绘制图形、作用域、添加阴影、清理、剪切等功能,本节将继续为大家分享canvas
的基础用法,同时也是最后一节基础知识分享,之后的内容,我们将会进入到对webgl
的分享中。
1. 文本绘制
首先我们要提到的是绘制文本,在canvas
的开发过程中,文本的内容是肯定会存在的。本小节就来给大家分享下如何渲染文本。
1.1 绘制空心和实心文本
canvas
中提供了两种绘制文本的方法,分别是绘制实心文本和空心文本,它们的方法分别是:
- strokeText(text, x, y, maxWidth): 绘制空心文本
- fillText(text, x, y, maxWidth): 绘制实心文本
参数介绍:
- text: 要绘制的文本内容
x, y
: 坐标点,文本左上角的坐标点- maxWidth: 允许渲染的最大像素宽度
栗子:
// 绘制实心文本
c.fillText('hello world', 100, 100); // 将 hello world 这个内容从 100 100 这个点开始渲染。
// 绘制空心文本
c.strokeText('hello world', 200, 200);
如果这里你的字体是默认大小,可能会看不到空心效果。改变字体大小在下文中有分享到。
1.2 改变文本样式
如果我们想修改字体的颜色,可以根据 绘制图形 一节中的方法,使用 strokeStyle、fillStyle
来修改。
1. 要设置实心文本字体为蓝色
c.fillStyle = 'blue';
c.fillText('hello world', 100, 100);
2. 要设置空心字体为红色
c.strokeStyle = 'yellow';
c.strokeText('hello world', 200, 200);
1.3 改变文本大小和字体样式
修改字体大小和字体样式需要用到 font = '字体大小 字体样式’
属性。
如:把字体改为 宋体 40px。
c.font = '40px 宋体';
如果是特殊的字体,会出现不支持的现象。
1.4 修改文本对齐方式
文本对齐方式分为 垂直 和 水平 对齐方式。
1. 垂直方向对齐。
这里需要用到 textBaseLine
这个属性。意为按照基线对齐。它有6个值,分别是:
- alphabetic: 默认值,意为普通的字母基线。可理解为四线三格的第三条线。
- top:文字头部对齐基线
- hanging:悬挂基线,与top稍有不同
- middle:文字中部对齐
- ideographic:表意基线。稍难理解,可看示意图
- bottom:文字底部对齐基线
示例:
// 首先我们画一条基准线,让文字按照这条线对齐
c.strokeStyle = 'blue';
c.moveTo(5, 100);
c.lineTo(700, 100);
c.stroke();
c.font = '20px 宋体';
// 枚举可用的对齐方式。
c.textBaseline = 'top';
c.fillText('Top', 5, 100);
c.textBaseline = 'bottom';
c.fillText('Bottom', 100, 100);
c.textBaseline = 'middle';
c.fillText('Middle', 200, 100);
c.textBaseline = 'alphabetic';
c.fillText('Alphabetic', 300, 100);
c.textBaseline = 'hanging';
c.fillText('Hanging', 400, 100);
c.textBaseline = 'ideographic';
c.fillText('ideographic', 500, 100);
示例图:
2. 水平居中
水平居中需要使用 textAlign
属性。同样也是基于基准线对齐,有5个属性值。
- start: 默认。文本在指定的位置开始。
- end: 在指定的位置结束
- center: 文本中心被放在指定位置
- left: 文本左对齐
- right: 文本右对齐
栗子:
// 创建基准线
c.strokeStyle = 'blue';
c.moveTo(150, 20);
c.lineTo(150, 400);
c.stroke();
c.font = '30px 宋体';
// 枚举可用的对齐方式。
c.textAlign = 'start';
c.fillText('start', 150, 50);
c.textAlign = 'end';
c.fillText('end', 150, 100);
c.textAlign = 'left';
c.fillText('left', 150, 150);
c.textAlign = 'center';
c.fillText('center', 150, 200);
c.textAlign = 'right';
c.fillText('right', 150, 250);
示例图:
3. 不固定宽高的画布水平居中
对于宽度不固定的画布,我们使用 textAlign
的作用就不太大了。因为此时我们需要根据画布的宽度进行实时计算。此时我们需要获得两个数值。画布宽度和字体宽度。画布宽度比较简单,使用 ctx.width
就可以获取。
字体的宽度。需要用到 measureText(text)
方法。此方法可根据你设置的字体大小来返回传入文本的像素宽度。
栗子:
c.font = '20px 宋体'
const textData = c.measureText('hello world');
console.log(textData.width) // 84
设置字体宽度为 20px
,则渲染后的 hello world
占据的像素宽度为 84px
(不同浏览器之间会有差异)
这样我们就可以得到水平居中的计算方式
文本x坐标 = (画布宽 - 文本宽)/ 2
const x = (ctx.width - c.measureText('hello world')) / 2;
2. 动画
2.1 状态保存与恢复
分享动画之前 ,我们先来介绍 save 和 restore
这两个方法。因为我们在处理动画的过程中,避免不了对画布进行旋转、平移和缩放的操作。从而导致之前或之后的绘制出现错乱。而``save 和 restore` 这两个方法就可以避免这个问题。
-
save
: 保存当前canvas
的状态。 -
restore
: 恢复之前保存的状态。
2.2 变换
说到动画,无非就是对图形的旋转、缩放、平移这几项内容。canvas
中提供了一系列的方法。
- translate(x, y): 平移。可改变当前画布的原点位置。
- rotate(deg) :旋转。其中 deg 代表的是弧度制。(角度转弧度请看初始canvas(一)的内容)
- scale(x,y): 缩放,
x
代表x轴缩放。y
代表y轴缩放。
栗子:
// 原始矩形
c.save()
c.fillRect(10, 10, 100, 100);
c.restore()
// 平移50px
c.save()
c.translate(50, 50);
c.fillRect(10,10,100,100);
c.restore()
// 旋转45度
c.save()
c.rotate(45 * Math.PI / 180);
c.fillRect(210, 110, 100, 100)
c.restore()
// x轴缩放0.5 y轴缩放1.1
c.save()
c.scale(0.5, 1.1)
c.fillRect(410, 210, 100, 100)
c.restore()
注意:translate
平移之后是可以改变画布原点的位置的,此时如果我们需要让某个图形围绕自身旋转,则需要将图像的中心点位于画布圆点上。如下方代码所示:
// 将画布中心移入到 50,50 这个点
c.translate(50, 50);
setInterval(() => {
// 每次绘制之前先清空画布,这里的原点已经在50,50这个位置了。所以需要从 -50这里开始清理。
c.clearRect(-50, -50, ctx.width, ctx.height);
// 每次旋转 1 度
c.rotate(Math.PI / 180);
// 绘制实心矩形。
c.fillRect(-25,-25, 50,50);
}, 16)
这里就可以得到一个围绕自身旋转的实心矩形。
2.3 transform 矩阵操作
方法接收 6
个参数。transform(a,b,c,d,e,f)
其中,
-
平移:涉及到
e, f
两个参数 -
缩放:涉及到
a, d
两个参数 -
拉伸:涉及到
b, c
两个参数 -
旋转:涉及到
a, b, c, d
四个参数
此方法在后续的讲解中还会出现,并且方法不太好理解,这里只简单说明。不做过多介绍。
3. 渐变
本小节来说下如何给图形添加渐变色。渐变色也是我们经常可以用到的功能。添加渐变色我们需要用到下面这两个方法
- createLinearGradient(sx,sy,ex,ey) 经向渐变
- createRadialGradient (sx,sy,sr,ex,ey,er) 环形渐变
sx, sy, sr
代表的是起始点渐变圆的原点坐标和半径,ex, ey, er
代表的是终止点渐变圆的原点坐标和半径。渐变方法返回一个对象。我们可以使用这个返回对象的 addColorStop(position, color)
方法 执行添加颜色的操作。
position
表示渐变的百分比,也就是渐变的位置。值是0-1
之间的浮点数。
color
是要添加的颜色
下面,我们通过一个栗子来看下如何创建渐变图形。
栗子1 -- 径向渐变:
// 创建径向渐变,得到渐变对象。
const lg = c.createLinearGradient(10, 10, 200, 200);
// 通过渐变对象来添加颜色
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');
// 将得到的渐变色添加到填充样式中。
c.fillStyle = lg;
c.fillRect(100, 100, 200, 200);
栗子2 -- 环形渐变:
// 起始点和终止点圆心坐标相同,代表从同一点开始散发
const lg = c.createRadialGradient(150, 100, 5, 150, 100, 100);
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');
c.fillStyle = lg;
c.arc(150, 100, 100, 0, 2 * Math.PI);
c.fill();
渐变示意图:
4. 源目标和透明度
4.1 透明度设置
对于透明度设置我们只需要知道一个属性就可以。
- globalAlpha = value:
value
的取值范围在0-1
之间。代表当前画布的透明度是多少。
4.2 源目标设置
源与目标设置我们需要用到 globalCompositeOperation
这个属性,它有N
个属性值。这里我们就不一一介绍了,这里我们先绘制一个红色的矩形,再绘制一个蓝色的矩形,然后我们来看下设置不同的globalCompositeOperation
会出现什么情况。
图解:
有需要的话可根据上图进行筛查,看下自己需要哪种效果。对应设置。
5. 图片绘制和背景设置
5.1 图片绘制
对于图片的操作在日常的工作中肯定会经常用到。canvas
中也提供了对于图片操作的方法供开发人员使用。
注意:
在加载图片的时候,一定要确保的是要在图片加载完成之后再添加到画布中。因此可以给图片使用onload事件。
如:
const image = new Image();
image.onload = function () {
// 绘制图片操作
}
image.src = '图片链接';
接下来绘制图片的方法默认都是存在于 onload
事件中的。
drawImage
可接收3,5,9
个参数;- 三个参数
(img,x,y)
img
是图片对象,x,y
是图片在画布中的原点位置
- 五个参数
(img,x,y,imageWidth,imageHeight)
;- 前三个参数不变,
imageWidth,imageHeight
设置的是图片的宽和高
- 前三个参数不变,
- 九个参数
(img,x,y,imageWidth,imageHeight,imgx,imgy,imgw,imgh)
;- 前五个参数不改变,
imgx,imgy
表示从图片的这个点开始取像素。imgw,imgh
表示的是取多宽多高的像素。
- 前五个参数不改变,
- 三个参数
5.2 背景设置
通过createPattern(image, repetition)
可以为画布设置背景图像。
其中, image
代表的是图片对象。repetition
代表的是是否平铺,repeat:平铺, no-repeat:不平铺
6. 像素操作
canvas
最引入注目的功能就是对于像素点的操作。这个功能可以让我们实现众多绚丽的特效。希望小伙伴们在领悟了像素操作的真谛之后,也能做出绚丽的特效。这个我们也成为粒子效果;
对于像素操作,canvas
中提供了三个方法。
getImageData(x,y,w,h)
: 获取画布中指定位置的像素集合 前两个参数是你想要获取的原点位置,后两个参数是你想要获取的范围putImageData(data, x,y)
: 设置画布中指定位置的像素集合,前两个参数是你想要设置的原点位置createImageData(data)
: 直接生成新的像素矩阵,不用获取
栗子:
const data = c.getImageData(0, 0, 10, 10);
console.log(data);
/*
[
[1,2,3,4,5,6,7,8,9,10……],
…………
]
*/
这里我们通过 getImageData
可以获取到一个二维数组,代表获取到的点位图。
数组中,每四个元素是一组。分别代表 r,g,b,a
中的每一项。每个r,g,b
元素的取值范围为 0-255
,a
的取值范围为0-1
;
如果我们想对像素做操作,那就修改这些值,如图片取反、复古风、底片…………等等,都可以实现。
有兴趣的小伙伴可以探讨一下哟~
7. 曲线
arcTo(startx, starty, endx, endy, r)
- 此方法可以让我们创建弧形线条。
startx, starty
表示弧的起始点。endx, endy
表示弧的终点。r
表示你弧的半径。
- 此方法可以让我们创建弧形线条。
示例:
c.beginPath()
c.moveTo(20,20);
c.lineTo(100,20);
c.arcTo(150,20,150,70,10); // 创建弧
c.lineTo(150,120);
c.stroke()
quadraticCurveTo(cox, coy, endx, endy)
二次贝塞尔曲线- 贝塞尔曲线可以帮我们获得更加多变的曲线内容。
cox, coy
表示控制点坐标。endx, endy
表示结束点坐标。
- 贝塞尔曲线可以帮我们获得更加多变的曲线内容。
示例:
c.beginPath()
c.moveTo(20,20);
// 将控制点设置在线段中间,
c.quadraticCurveTo(60, 80, 100, 20)
c.stroke()
示例图:
除了这两种曲线,还有三次贝塞尔曲线。小伙伴们可以自己试验下,与二次贝塞尔曲线不同的是添加了一组控制点。
8. 事件
作为canvas
中唯二的两个可以获取到当前图形信息的事件。isPointInPath和isPointInStroke
的作用不可小觑。在很多针对图形的操作我们都需要用到这个方法。
方法也是比较简单。
isPointInPath(x, y)
接收两个参数,一个x坐标
一个y坐标
,判断当前坐标是否在图形之内。isPointInStroke(x, y)
接收两个参数,一个x坐标
一个y坐标
,判断当前坐标是否在空心图形边框上。
9. 将canvas转换为图片 -- toDataURL
最后一个来分享下如何将我们绘制好的图形保存下来。对之后的分享自己绘制的图形,在其他内容上显示等等等等,都可以用到。
将canvas
转换为图片,我们需要用到 toDataURL(type, encoderOptions)
,
type
可以设置我们想得到的类型。如: image/png、image/jpg…………
encoderOptions
可以设置图片的质量。
栗子:
const url = ctx.toDataURL('image/png')
console.log(url); // data:image/png;base64,……………………
注意:
这里我们是使用的 ctx
来转换图片,也就是使用 canvas
这个标签对象来转换。
到这里我们对于 canvas
的基础内容就分享完了,从下节开始,我们就要进入到对 webgl
的学习中了。
好了,今天的分享就到这里了,Bye~