Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

canvas性能优化 #36

Open
beiweiqiang opened this issue May 28, 2016 · 0 comments
Open

canvas性能优化 #36

beiweiqiang opened this issue May 28, 2016 · 0 comments

Comments

@beiweiqiang
Copy link
Contributor

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+

意外发现这个渲染出来是这样子
share01

优化后

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. 总结

Zhangjd added a commit that referenced this issue May 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants