canvas:关于canvas的使用(超详细的canvas知识体系讲解)

1. 关于canvas

1.1. 简介

1.1.1. 是 HTML5 新增的,一个可以使用脚本(通常为 JavaScript) 在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行实时视频处理和渲染。

1.1.2. 它最初由苹果内部使用自己 MacOS X WebKit 推出,供应用程序使用像仪表盘的构件和 Safari 浏览器使用。后来,有人通过 Gecko 内核的浏览器 (尤其是 Mozilla和Firefox),Opera 和 Chrome 和超文本网络应用技术工作组建议为下一代的网络技术使用该元素。

1.1.3. Canvas 是由 HTML 代码配合高度和宽度属性而定义出的可绘制区域。JavaScript 代码可以访问该区域,类似于其他通用的二维 API,通过一套完整的绘图函数来动态生成图形。

1.2. 注意事项

1.2.1. canvans是双标签

1.2.2. 如果不给 设置 widht、height 属性时,则默认 width为300、height 为 150,单位都是 px。也可以使用 css 属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现扭曲。所以,建议永远不要使用 css 属性来设置 的宽高

1.2.3. 由于某些较老的浏览器(尤其是 IE9 之前的 IE 浏览器)或者浏览器不支持 HTML 元素 ,在这些浏览器上只能能展示替代内容。

2. canvas的基本使用

2.1. 渲染上下文

if(!canvas.getContext) return;

2.2. 检测支持性

if(!canvas.getContext) return;

2.3. 代码模板

<canvas id="tutorial" width="300" height="300"></canvas><script type="text/javascript">function draw(){var canvas = document.getElementById('tutorial');if(!canvas.getContext) return;if(!canvas.getContext) return;ctx.fillStyle = "rgb(200,0,0)";//绘制矩形ctx.fillRect (10, 10, 55, 50);ctx.fillStyle = "rgba(0, 0, 200, 0.5)";ctx.fillRect (30, 30, 55, 50);}draw();</script>

3. 图形绘制

3.1. 方法汇总

3.1.1. fillRect(x, y, width, height):绘制一个填充的矩形

参数说明:x, y:指的是矩形的左上角的坐标。(相对于canvas的坐标原点)

3.1.2. strokeRect(x, y, width, height):绘制一个矩形的边框。

参数同上

3.1.3. clearRect(x, y, widh, height):清除指定的矩形区域,然后这块区域会变的完全透明。

参数同上

4. 路径绘制

4.1. 基本步骤

4.1.1. 创建路径起始点

4.1.2. 调用绘制方法去绘制出路径

4.1.3. 把路径封闭

4.1.4. 一旦路径生成,通过描边或填充路径区域来渲染图形。

4.2. 方法汇总

4.2.1. beginPath()

新建一条路径,路径一旦创建成功,图形绘制命令被指向到路径上生成路径

4.2.2. moveTo(x, y)

把画笔移动到指定的坐标(x, y)。相当于设置路径的起始点坐标。

4.2.3. closePath()

闭合路径之后,图形绘制命令又重新指向到上下文中

4.2.4. stroke()

通过线条来绘制图形轮廓

4.2.5. fill()

通过填充路径的内容区域生成实心的图形

4.2.6. lineTo(x,y)

绘制一条从当前位置到指定坐标(x,y)的直线.

4.2.7. arc(x, y, r, startAngle, endAngle, anticlockwise)

以(x, y) 为圆心,以r 为半径,从 startAngle 弧度开始到endAngle弧度结束。anticlosewise 是布尔值,true 表示逆时针,false 表示顺时针(默认是顺时针)。

4.2.8. arcTo(x1, y1, x2, y2, radius)

根据给定的控制点和半径画一段圆弧,最后再以直线连接两个控制点,radius标识半径
例图:


4.3. 贝塞尔曲线

4.3.1. 一次贝塞尔曲线其实是一条直线

4.3.2. 二次贝塞尔曲线

quadraticCurveTo(cp1x, cp1y, x, y)
参数说明: 参数 1 和 2:控制点坐标,参数 3 和 4:结束点坐标
例图:

4.3.3. 三次贝塞尔曲线

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
参数说明: 参数 1 和 2:控制点 1 的坐标,参数 3 和 4:控制点 2 的坐标,参数 5 和 6:结束点的坐标
例图:


5. 样式&颜色

5.1. 基本方法

5.1.1. fillStyle = color 设置图形的填充颜色

color可以是css 颜色值的字符串、渐变对象或者图案对象

5.1.2. strokeStyle = color 设置图形轮廓的颜色

5.1.3. Transparency(透明度) globalAlpha = transparencyValue

这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0

5.1.4. lineWidth=1

线宽。只能是正值。默认是 1.0。
起始点和终点的连线为中心,上下各占线宽的一半。

5.1.5. lineCap = type

butt:线段末端以方形结束
round:线段末端以圆形结束
square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
例图:

5.1.6. lineJoin = type

round 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。
bevel 在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
miter(默认) 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
例图:

5.2. 虚线

5.2.1. setLineDash() 方法

接受一个数组,来指定线段与间隙的交替(例ctx.setLineDash([20, 5]))

5.2.2. lineDashOffset 属性

设置起始偏移量(例ctx.lineDashOffset = -1)

5.2.3. getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组

6. 文本绘制

6.1. 基本方法

6.1.1. fillText(text, x, y [, maxWidth])

在指定的 (x,y) 位置填充指定的文本,绘制的最大宽度是可选的。

6.1.2. strokeText(text, x, y [, maxWidth])

在指定的 (x,y) 位置绘制文本边框,绘制的最大宽度是可选的。

6.2. 文本样式

6.2.1. font = value

当前我们用来绘制文本的样式。这个字符串使用和 CSS font 属性相同的语法。 默认的字体是 10px sans-serif。

6.2.2. textAlign = value

文本对齐选项。可选的值包括:start, end, left, right or center。 默认值是 start

6.2.3. textBaseline = value

基线对齐选项,可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。

6.2.4. direction = value

文本方向。可能的值包括:ltr, rtl, inherit。默认值是 inherit

7. 图片绘制

7.1. 注意

考虑到图片是从网络加载,如果 drawImage 的时候图片还没有完全加载完成,则什么都不做,个别浏览器会抛异常。所以我们应该保证在 img 绘制完成之后再 drawImage

7.2. 绘制方法模板

<img src="图片路径" alt="" width="300"><br><canvas id="tutorial" width="600" height="400"></canvas>function draw(){var canvas = document.getElementById('tutorial');if (!canvas.getContext) return;var ctx = canvas.getContext("2d");var img = document.querySelector("img");ctx.drawImage(img, 0, 0);}

7.3. drawImage()方法详解

7.3.1. 基本绘制:drawImage(img,x,y)

参数 1:要绘制的 img 参数 2、3:绘制的 img 在 canvas 中的坐标

7.3.2. 图片缩放:drawImage(image, x, y, width, height)

width 和 height,这两个参数用来控制 当canvas 画入时应该缩放的大小

7.3.3. 切片:drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用;2-5 个是定义图像源的切片位置和大小,6-9 个则是定义切片的目标显示位置和大小
例图:

8. 状态的保存和恢复

8.1. 说明

状态的保存和恢复是绘制复杂图型的必要操作,简单的说就是绘制完一个图形进行保存再继续再保存的图形上进行绘制,直到完成一个目标的图形。

8.2. save()方法

Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存

8.3. restore()

每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复(类似数组的 pop())

8.4. 一个例子

function draw(){var canvas = document.getElementById('tutorial');if (!canvas.getContext) return;var ctx = canvas.getContext("2d");ctx.fillRect(0, 0, 150, 150); // 使用默认设置绘制一个矩形ctx.save(); // 保存默认状态ctx.fillStyle = 'red' // 在原有配置基础上对颜色做改变ctx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形ctx.save(); // 保存当前状态ctx.fillStyle = '#FFF' // 再次改变颜色配置ctx.fillRect(30, 30, 90, 90); // 使用新的配置绘制一个矩形ctx.restore(); // 重新加载之前的颜色状态ctx.fillRect(45, 45, 60, 60); // 使用上一次的配置绘制一个矩形ctx.restore(); // 加载默认颜色配置ctx.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形}draw();

例图:


9. 合成

9.1. 说明

通过状态保存和恢复可以通过再一个图形上不断叠加完成一个复杂图形,但这是远远不够的,有时需要限制绘制顺序,这就可以用合成来实现

9.2. 方法:globalCompositeOperation = type

9.2.1. 默认新图覆盖老图

例图:


9.2.2. source-in 仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)

例图:


9.2.3. source-out 仅仅显示新图像与老图像没有重叠的部分,其余部分全部透明。(老图像也不显示)

例图:


9.2.4. source-atop 新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。

例图:


9.2.5. destination-over 新图像会在老图像的下面

例图:


9.2.6. destination-in 仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。

例图:


9.2.7. destination-out 仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。

例图:


9.2.8. destination-atop 老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面

例图:


9.2.9. lighter 新老图像都显示,但是重叠区域的颜色做加处理。

例图:


9.2.10. darken 保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)

例图:

9.2.11. lighten 保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)

例图:

9.2.12. xor 重叠部分会变成透明。

例图:

9.2.13. copy 只有新图像会被保留,其余的全部被清除(变透明)。

例图:

10. 变形

10.1. 方法汇总(与css3基本相同)

10.1.1. translate(x, y)

用来移动 canvas 的原点到指定的位置,x 是左右偏移量,y 是上下偏移量
在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。又如果你是在一个循环中做位移但没有保存和恢复 canvas 的状态,很可能到最后会发现怎么有些东西不见了,那是因为它很可能已经超出 canvas 范围以外了

10.1.2. rotate(angle)

angle:旋转的角度,它是顺时针方向的,以弧度为单位的值,旋转的中心是坐标原点

10.1.3. scale(x, y)

x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值

11. 动画

11.1. 基本步骤

11.1.1. 清空 canvas 再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是 clearRect() 方法。

11.1.2. 保存 canvas 状态 如果在绘制的过程中会更改 canvas 的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下 canvas 的状态

11.1.3. 绘制动画图形这一步才是真正的绘制动画帧

11.1.4. 恢复 canvas 状态如果你前面保存了 canvas 状态,则应该在绘制完成一帧之后恢复 canvas 状态。

11.2. 常用方法

11.2.1. setInterval()

11.2.2. setTimeout()

11.2.3. requestAnimationFrame()

11.3. 一个简单的小案例(动态代码雨效果)

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>* {margin: 0;padding: 0;overflow: hidden;}</style></head><body><canvas id="bg"></canvas><script>// 获取对象const cvs = document.getElementById("bg");// 设置canvas画布宽高const width = window.innerWidth;const height = window.innerHeight;cvs.width = width;cvs.height = height;// 返回一个用于在画布上绘图的环境const ctx = cvs.getContext("2d");// 定义每列的宽度const columnWidth = 20;// 生成的列数const columnCount = Math.floor(window.innerWidth / columnWidth)// 创建数组const columnNextIndexes = new Array(columnCount);// 全部用1填充columnNextIndexes.fill(1);// 绘画function draw() {// 背景颜色ctx.fillStyle = 'rgba(240,240,240,0.2)';// fillRect(x1, y1, width, width) 画图形ctx.fillRect(0, 0, width, height);// 设置颜色ctx.fillStyle = getRandomColor();const fz = 20;// 字体样式ctx.font = `${fz}px Calibri`;for (let i = 0; i < columnCount; i++) {// x坐标const x = i * columnWidth;// y坐标const y = fz * columnNextIndexes[i];// 填充内容ctx.fillText(getRandomChar(), x, y);// 判断是否超出可视范围if (y > height && Math.random() > 0.99) {columnNextIndexes[i] = 0;} else {columnNextIndexes[i]++}}}draw()setInterval(draw, 40)// 随机颜色function getRandomColor() {const fontColor = ["#33b5e5","#0099cc","#aa66cc","#9933cc","#669900","#ffbb33","#ff8800","#ff4444","#cc0000"]return fontColor[Math.floor(Math.random() * fontColor.length)]}// 随机字符function getRandomChar() {const str = "console.log('hello world')";return str[Math.floor(Math.random() * str.length)]}</script></body></html>

相关推荐

相关文章