canvas 笔记

canvas教程

一. 概述

长久以来,web上的动画都是Flash。比如动画广告、游戏等等,基本上都是F1ash实现的。Flash是有缺点的,比如需要安装 Adobe Flash Player,漏洞多,重量比较大。卡顿和不流畅等等

1.1 简介

HTML5提出了一个新的 canvas标签,彻底颠覆了Flash的主导地位。无论是广告、游戏都可以使用 canvas实现了, Canvas是一个轻量级的画布,我们使用 Canvas进行 JavaScript的编程,不需要增加额外的插件,性能也很好,不卡顿,在手机中也很流畅

二. 基本使用

1
2
3
<canvas width="400" height="500" id="mycanvas">
当前浏览器版本不支持,请升级浏览器
</canvas>

canvas的标签属性只有两个, width和 height.。表示的是 canvas画布的宽度和高度。注意 canvas的 width和 height不要用css的样式来设置,如果使用css的样式来设置,画布会失真,会变形 标签对儿里面的文字是用来提示低版本浏览器(IE6/7/8)

方法/属性 描述
getContext() 得到画布上下文,上下文有两个,2d的上下文和3d的上下文
fillStyle 设置颜色
fillRect(x,y,width,height) 方法绘制“已填色”的矩形。默认的填充颜色是黑色。

三.canvas的编程思想

3.1 像素化

我们使用 canvas绘制了一个图形,一旦绘制成功了, canvas就像素化了他们。 canvas没有能力,从画布上再次得到这个图形,也就是说我们没有能力去修改已经在画布上的内容。这个就是 canvas比较轻量的原因,Flash重的原因之一就有它可以通过对应的api得到已经上“画布”的内容然后再次绘制,如果我们想要让这个 canvas图形移动,必须按照清屏-更新-渲染的逻辑进行编程,总之就是重新再画一次

3.2 动画思想

清屏-更新-渲染,这个思想就可以为 canvas的动画思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var canvas=document.getElementById("mycanvas");
var ctx=canvas.getContext("2d")
ctx.fillStyle="blue"
// 设置信号量
var left=10;
setInterval(()=>{
//清除画布
ctx.clearRect(0,0,700,600)
// 更新信号量
left++;
ctx.fillRect(left,left,100,100)
if(left==700){
left=10
}
},4)

实际上,动画的生存就是相关静态画面连续插放了,这个就是动画的过程。我们把每一次绘制的静态画面叫做 " 一帧 ",时间的间隔(定时器的间隔)就表示的是帧的间隔

3.3 面向对象实现 canvas 动画

因为 canvas不能得到已经上屏的对象,所以我们要维持对象的状态。在 canvas动画中,我们都使用面向对象来进行编程,因为我们可以使用面向对象的方式来维持 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
// 获取画布
var can = document.getElementById("can")
var ctx = can.getContext("2d");
// 绘制方法
function Rect(x, y, w, h, color) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color
}
// 更新方法
Rect.prototype.update = function () {
this.x++;
}
// 渲染
Rect.prototype.render = function () {
// 设置颜色
ctx.fillStyle = this.color;
// 渲染
ctx.fillRect(this.x, this.y, this.w, this.h);
}
// 实例化
var r1 = new Rect(100, 100, 50, 50, "#91d5ff")
// 动画过程
setInterval(() => {
//清屏
ctx.clearRect(0, 0, can.width, can.height)
//更新
r1.update()
// 渲染
r1.render()
}, 5)

​ 动画过程在主定时器里面,每一帧都会调动实例的更新和渲染方法

四. canvas绘制功能

方法/属性 描述
fillStyle 设置填充颜色
fillRect(x,y,width,height) 方法绘制“已填色”的矩形。默认的填充颜色是黑色。
strokeStyle 设置边框颜色
strokeRect(x,y,width,height) 方法绘制矩形边框。默认的填充颜色是黑色。
clearRect(x,y,width,height) 清除画布内容
globalAlpha 设置透明度 0-1

4.1 绘制路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建路径
ctx.beginPath()
// 移动绘制点
ctx.moveTo(100,100)
// 描述行进路径
ctx.lineTo(200,300);
ctx.lineTo(300,230);
ctx.lineTo(440,290);
ctx.lineTo(380,50);
// 封闭路径
ctx.closePath()
// 设置颜色
ctx.strokeStyle="#91d5ff"
// 绘制不规则图形
ctx.stroke()
// 填充不规则图形
ctx.fill()

绘制路径图

4.2 绘制圆弧

1
arc(x, y, radius, startAngle, endAngle, anticlockwise)
  • x,y为绘制圆弧所在圆上的圆心坐标。
  • radius为半径。
  • startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准。
  • 参数anticlockwise为一个布尔值。为true时,是逆时针方向,否则顺时针方向。

注意:arc()函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式:

弧度=(Math.PI/180)*角度。

1
2
3
4
5
6
7
// 创建路径
ctx.beginPath();
// 圆周长 2π 2*3.14≈7 2*Math.PI
ctx.arc(200,200,100,0,2*Math.PI,false)
// ctx.arc(200,200,100,0,0.3,false)
// 绘制
ctx.stroke()

canvas实现鼠标跟随炫彩小球

canvas实现炫彩小球弹弹

4.3 线型

我们可以利用lineWidth设置线的粗细,属性值必须是数字,默认是1.0。没有单位

1
2
3
4
5
6
ctx.beginPath();
ctx.moveTo(100,150)
ctx.lineTo(200,200)
ctx.lineTo(300,50)
ctx.lineWidth=10
ctx.stroke()

线型教程

4.4 文本

1
2
3
4
5
// 设置文字
ctx.font="30px 宋体"
// 设置文字对齐方式
ctx.textAlign="start"
ctx.fillText("Hello Canvas",100,100)

4.5 渐变

  • 线型渐变
1
2
3
4
5
6
7
8
// 渐变
var linear=ctx.createLinearGradient(0, 0, 200, 200);
linear.addColorStop(0,"red");
linear.addColorStop(0.5,"#91d5ff");
linear.addColorStop(0.8,"#ffec3d");
linear.addColorStop(1,"blue")
ctx.fillStyle=linear
ctx.fillRect(10,10,200,100)

4.6 阴影

1
2
3
4
5
6
7
8
// 阴影
ctx.shadowOffsetX=10 // 左右偏移
ctx.shadowOffsetY=10 // 上下偏移
ctx.shadowBlur=3; // 模糊度
ctx.shadowColor="red"; // 颜色
// 设置文字
ctx.font="30px 宋体"
ctx.fillText("Hello Canvas",100,100)

五. 图片使用

1
2
3
4
5
6
7
8
 // 创建image元素
var img=new Image();
// 设置src地址
img.src="https://tva3.sinaimg.cn/large/006djwNZgy1gmqxcekdm8j31hc0u0dln.jpg"
// 必须在onload 之后绘制图片
img.onload=function(){
ctx.drawImage(img,100,100,200,100)
}
  • 4个参数
1
drawImage(img,x,y,width,height)

kfdjhgfkd9856745

1
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
  1. 前4个参数指的是你在图片中设置切片的宽度和高度,以及切片位置
  2. 后4个参数指的是切片在画布上的位置和切片的宽度和高度
image-20210213111523157

六.资源管理器

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
 // 游戏类
function Game() {
this.dom = document.querySelector("canvas");
this.ctx = this.dom.getContext("2d");

// 添加属性,保存需要的图片地址
this.R = {
"01": "https://tvax3.sinaimg.cn/large/006djwNZgy1gkyvxt1exaj33y8280b2c.jpg",
"02": "https://tva1.sinaimg.cn/large/006djwNZgy1gkyzq80yobj31hc0u0n4r.jpg",
"03": "https://tva3.sinaimg.cn/large/006djwNZgy1gmqxcekdm8j31hc0u0dln.jpg",
"04": "https://tva4.sinaimg.cn/large/006djwNZgy1gmqxee8qo6j31hc0u0qcr.jpg"
}
// 获取资源图片的总数
var allAmount = Object.keys(this.R).length
// 计数器
var count = 0
// 遍历对象获取每一个地址
for (k in this.R) {
var src = this.R[k]
// 创建图片
this.R[k] = new Image()
// 设置图片地址
this.R[k].src = src;
// 判断图片是否加载完成
var self = this
this.R[k].onload = function () {
// 计数
count++;
// 清屏
self.ctx.clearRect(0, 0, 600, 500)
self.ctx.font = "16px Arial"
// 设置资源加载文案
self.ctx.fillText("图片已加载:" + count + "/" + allAmount, 10, 50)
}
}

}
console.log(new Game());

七.变形

7.1 概述

save()

保存画布(canvas)的所有状态

restore()

save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。一个绘画状态包括:

你可以调用任意多次 save方法。每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。

7.2 translate

  • translate和CSS3的 translate属性一样也是发挥着空间平移作用
1
2
3
4
5
6
7
8
// 保存
ctx.save();
ctx.translate(50,50)
ctx.fillRect(0,0,120,120)
// 恢复
ctx.restore()
// 渲染位置是没有存档之前的位置
ctx.fillRect(0,200,120,120)
image-20210213124807029
  • 变形实际上都是将整个画布进行的变形,所以如果一旦变形操作多了,画布将变得不可控
  • 如果使用到变形,一定记住下面的规律:变形之前要先备份,将世界和平的状态进行备份,然后再变形,变形完毕后一定要恢复到世界和平的样子,不要影响下一次的操作

7.3 rotate

1
2
3
4
5
6
7
8
9
// 保存
ctx.save();
ctx.translate(200,100)
ctx.rotate(1)
ctx.fillRect(0,0,120,120)
// 恢复
ctx.restore()
// 渲染位置是没有存档之前的位置
ctx.fillRect(0,200,120,120)

rotate(angle)

这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。

旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate方法。

7.4 scale

1
2
3
4
5
6
7
8
ctx.save();
ctx.translate(200,100)
ctx.scale(0.6,0.6)
ctx.fillRect(0,0,120,120)
// 恢复
ctx.restore()
// 渲染位置是没有存档之前的位置
ctx.fillRect(0,200,120,120)

scale 方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比1小,会缩小图形, 如果比1大会放大图形。默认值为1, 为实际大小。

7.5 Transforms

最后一个方法允许对变形矩阵直接修改。

1
2
transform(a, b, c, d, e, f)
// 如果任意一个参数是`Infinity`,变形矩阵也必须被标记为无限大,否则会抛出异常。

这个函数的参数各自代表如下:

  • a(m11) 水平方向的缩放
  • b(m12) 竖直方向的倾斜偏移
  • c(m21) 水平方向的倾斜偏移
  • d(m22) 竖直方向的缩放
  • e(dx) 水平方向的移动
  • f(dy) 竖直方向的移动

八.合成

  • 合成其实就是我们常见的蒙板状态,本质就是如何进行压盖,如何进行显示
1
2
3
4
5
6
ctx.fillStyle="#91d5ff"
ctx.fillRect(100,100,100,100)
ctx.fillStyle="#ffc069"
ctx.beginPath()
ctx.arc(200,200,60,0,7,false)
ctx.fill()
image-20210213190925696
1
ctx.globalCompositeOperation="destination-over"
image-20210213191252885