初识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-255a 的取值范围为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~

posted @ 2020-12-10 20:05  Sunmus  阅读(136)  评论(0编辑  收藏  举报