canvas性能优化

canvas性能优化

十一月 16, 2020

概念介绍

canvas是H5新增的一个可以使用脚本(JavaScript)来绘制图形的HTML元素,我们可以用它来绘制图表,制作图片或者制作简单的动画。

常用API

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// 获取上下文
getContext('2d')
// 改变颜色
fillStyle('rgba(0, 0, 0, .5)')
strokeStyle = color
// 绘制矩形
fillRect(x, y, width, height)
// 绘制矩形边框
strokeRect(x, y, width, height)
// 清除指定矩形区域
clearRect(x, y, width, height)
// 绘制路径
beginPath()
closePath()
stroke()
fill()
// 移动到
moveTo(x, y)
// 绘制一条从当前位置到指定x以及y位置的直线。
lineTo(x, y)
// 绘制圆弧(画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成)
arc(x, y, radius, startAngle, endAngle, anticlockwise)
// 二次贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y)
// 三次贝塞尔曲线
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
// 为了简化代码和提高性能,Path2D对象已可以在较新版本的浏览器中使用,用来缓存或记录绘画命令,这样你将能快速地回顾路径。
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');

var rectangle = new Path2D();
rectangle.rect(10, 10, 50, 50);

var circle = new Path2D();
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Math.PI);

ctx.stroke(rectangle);
ctx.fill(circle);
}
}
// 全局透明度
globalAlpha = transparencyValue
// 绘制文本
fillText(text, x, y [, maxWidth])
// 绘制图片(支持缩放以及切片)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
// 状态的保存和恢复 Saving and restoring state
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');

ctx.fillRect(0,0,150,150); // 使用默认设置绘制一个矩形
ctx.save(); // 保存默认状态

ctx.fillStyle = '#09F' // 在原有配置基础上对颜色做改变
ctx.fillRect(15,15,120,120); // 使用新的设置绘制一个矩形

ctx.save(); // 保存当前状态
ctx.fillStyle = '#FFF' // 再次改变颜色配置
ctx.globalAlpha = 0.5;
ctx.fillRect(30,30,90,90); // 使用新的配置绘制一个矩形

ctx.restore(); // 重新加载之前的颜色状态
ctx.fillRect(45,45,60,60); // 使用上一次的配置绘制一个矩形

ctx.restore(); // 加载默认颜色配置
ctx.fillRect(60,60,30,30); // 使用加载的配置绘制一个矩形
}
// 移动 Translating
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
ctx.save();
ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
ctx.translate(10 + j * 50, 10 + i * 50);
ctx.fillRect(0, 0, 25, 25);
ctx.restore();
}
}
}
// 旋转 Rotating
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.translate(75,75);

for (var i=1;i<6;i++){ // Loop through rings (from inside to out)
ctx.save();
ctx.fillStyle = 'rgb('+(51*i)+','+(255-51*i)+',255)';

for (var j=0;j<i*6;j++){ // draw individual dots
ctx.rotate(Math.PI*2/(i*6));
ctx.beginPath();
ctx.arc(0,i*12.5,5,0,Math.PI*2,true);
ctx.fill();
}

ctx.restore();
}
}
// 缩放 Scaling
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');

// draw a simple rectangle, but scale it.
ctx.save();
ctx.scale(10, 3);
ctx.fillRect(1, 10, 10, 10);
ctx.restore();

// mirror horizontally
ctx.scale(-1, 1);
ctx.font = '48px serif';
ctx.fillText('MDN', -135, 120);
}
// 变形 Transforms
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');

var sin = Math.sin(Math.PI/6);
var cos = Math.cos(Math.PI/6);
ctx.translate(100, 100);
var c = 0;
for (var i=0; i <= 12; i++) {
c = Math.floor(255 / 12 * i);
ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
ctx.fillRect(0, 0, 100, 10);
ctx.transform(cos, sin, -sin, cos, 0, 0);
}

ctx.setTransform(-1, 0, 0, 1, 100, 100);
ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
ctx.fillRect(0, 50, 100, 100);
}
// 组合
globalCompositeOperation = type
// 裁切
clip()
/**
* 动画: 1.清空 canvas; 2.保存 canvas 状态; 3.绘制动画图形(animated shapes); 4.恢复 canvas 状态。
**/
setInterval(function, delay)
setTimeout(function, delay)
window.requestAnimationFrame() // 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。这个方法提供了更加平缓并更加有效率的方式来执行动画,当系统准备好了重绘条件的时候,才调用绘制动画帧。

性能优化

  1. 在离屏canvas上预渲染相似的图形或重复的对象
  2. 避免浮点数的坐标点,用整数取而代之
  3. 不要在用drawImage时缩放图像
  4. 使用多层画布去画一个复杂的场景
  5. 用CSS设置大的背景图
  6. 用CSS transforms特性缩放画布
  7. 关闭透明度
  8. 将画布的函数调用集合到一起(例如,画一条折线,而不要画多条分开的直线)
  9. 避免不必要的画布状态改变
  10. 有动画,请使用window.requestAnimationFrame() 而非window.setInterval()