-
Notifications
You must be signed in to change notification settings - Fork 31
Open
Labels
Description
canvas性能优化
欣(bei)然(bi)接受师父要求,做一个canvas优化的个人见解的小分享
(认识较浅,只能聊一点点,装不了比)
春招选了萝卜大战洞穴的题目,在动画展示上用到了canvas,做完以后在pc端运行当然很流畅,但是一到移动端实验就呵呵excuse me了。动画各种卡,各种掉帧。
然后就必须要进行canvas优化了,师父给我这个网站,以下是见解
1. 尽量少调用canvasAPI
用一种很low的方式来测试canvas性能
优化前
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 400;
canvas.height = 400;
var ctx = canvas.getContext("2d");
for (var i = 0; i < 400; i++) {
for (var j = 0; j < 400; j++) {
ctx.beginPath();
ctx.moveTo(i, j);
ctx.lineTo(i, j+1);
ctx.stroke();
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均330+
优化后
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 400;
canvas.height = 400;
var ctx = canvas.getContext("2d");
ctx.beginPath();
for (var i = 0; i < 400; i++) {
for (var j = 0; j < 400; j++) {
ctx.moveTo(i, j);
ctx.lineTo(i, j+1);
}
}
ctx.stroke();
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均32+
对这个我有很深的体会,因为那个任务里我主要用了这个优化方法。
比如在那个游戏里面,我渲染了上下两个边界,加之因为是像素级别的操作,所以调用api次数非常多。
换个角度思考,只渲染两个边界的中间部分,调用api的次数变为原来的一半。
2. 尽量少改变canvas状态
优化前
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
for (var i = 0; i < 500 ; i++) {
for (var j = 0; j < 500 ; j++) {
ctx.fillStyle = (j % 2 ? '#ff5252' : '#1976d2');
ctx.fillRect(j * 2, i * 2, 2, 2);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均220+
优化后
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
ctx.fillStyle = '#ff5252';
for (var i = 0; i < 500; i++) {
for (var j = 0; j < 500 / 2; j++) {
ctx.fillRect((j * 2) * 2, i * 2, 2, 2);
}
}
ctx.fillStyle = '#1976d2';
for (var i = 0; i < 500; i++) {
for (var j = 0; j < 500 / 2; j++) {
ctx.fillRect((j * 2 + 1) * 2, i * 2, 2, 2);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均120+
3. 重新渲染的范围尽量小
这个当然会优化,所以就不举例了~
4. 不要使用阴影
优化前
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 2;
ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
for (var i = 0; i < 300 ; i++) {
for (var j = 0; j < 300 ; j++) {
ctx.fillRect(j * 2, i * 2, 2, 2);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均2800+
优化后
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
for (var i = 0; i < 300 ; i++) {
for (var j = 0; j < 300 ; j++) {
ctx.fillRect(j * 2, i * 2, 2, 2);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均40+
5. 像素级别操作尽量用整数
优化前
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
for (var i = 0; i < 1000 ; i++) {
for (var j = 0; j < 1000 ; j++) {
ctx.fillRect(j * 0.99, i * 0.99, 0.99, 0.99);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均1200+
优化后
var start_time = (new Date()).getTime();
var canvas = document.getElementById("canvas");
canvas.width = 1000;
canvas.height = 1000;
var ctx = canvas.getContext("2d");
for (var i = 0; i < 1000 ; i++) {
for (var j = 0; j < 1000 ; j++) {
ctx.fillRect(j * 1, i * 1, 1, 1);
}
}
var end_time = (new Date()).getTime();
console.log(end_time - start_time); // 平均440+
6. 总结
无
