你还在抱怨自己写的canvas demo徘徊在10帧以下吗?你还在烦恼打开自己写的应用就听见CUP风扇转吗?你正在写一个javascript Canvas库吗?那么下面九点就是你必须知道的! 一.预渲染 错误代码: var canvas = document.getElementById( "myCanvas" ); var cont
你还在抱怨自己写的canvas demo徘徊在10帧以下吗?你还在烦恼打开自己写的应用就听见CUP风扇转吗?你正在写一个javascript Canvas库吗?那么下面九点就是你必须知道的!
一.预渲染
错误代码:
1 2 3 4 5 6 7 8 9 10 | <span> var </span><span>canvas = document.getElementById(</span><span> "myCanvas" </span><span>);
</span><span> var </span><span>context = </span><span>this</span><span>.canvas.getContext(</span><span> '2d' </span><span>);
</span><span> var </span><span>drawAsync = eval (Jscex.compile(</span><span> "async" </span><span>, </span><span> function </span><span>() {
</span><span> while </span><span>(</span><span>true</span><span>) {
drawMario(context);
$await (Jscex.Async.sleep(</span><span>1000</span><span>));
}
}))
drawAsync().start();
</span>
|
Copy after login
正确代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span> var </span><span>canvas = document.getElementById(</span><span> "myCanvas" </span><span>);
</span><span> var </span><span>context = </span><span>this</span><span>.canvas.getContext(</span><span> '2d' </span><span>);
</span><span> var </span><span>m_canvas = document.createElement(</span><span> 'canvas' </span><span>);
</span><span>m_canvas.width = </span><span>64</span><span>;
m_canvas.height = </span><span>64</span><span>;
</span><span> var </span><span>m_context = m_canvas.getContext(</span><span> '2d' </span><span>);
drawMario(m_context);
</span><span> var </span><span>drawAsync = eval (Jscex.compile(</span><span> "async" </span><span>, </span><span> function </span><span>() {
</span><span> while </span><span>(</span><span>true</span><span>) {
context.drawImage(m_canvas, </span><span>0</span><span>, </span><span>0</span><span>);
$await (Jscex.Async.sleep(</span><span>1000</span><span>));
}
}))
drawAsync().start();
</span>
|
Copy after login
这里m_canvas的宽度和高度控制得越小越好。
二.尽量少调用canvasAPI
错误代码:
1 2 3 4 5 6 7 8 9 | <span> for </span><span>(</span><span> var </span><span>i = </span><span>0</span><span>; i <span>1</span><span>; i++) {
</span><span> var </span><span>p1 = points[i];
</span><span> var </span><span>p2 = points[i + </span><span>1</span><span>];
context.beginPath();
context.moveTo(p1.x, p1.y);
context.lineTo(p2.x, p2.y);
context.stroke();
}
</span></span>
|
Copy after login
正确代码:
1 2 3 4 5 6 7 8 9 | <span>context.beginPath();
</span><span> for </span><span>(</span><span> var </span><span>i = </span><span>0</span><span>; i <span>1</span><span>; i++) {
</span><span> var </span><span>p1 = points[i];
</span><span> var </span><span>p2 = points[i + </span><span>1</span><span>];
context.moveTo(p1.x, p1.y);
context.lineTo(p2.x, p2.y);
}
context.stroke();
</span></span>
|
Copy after login
三.尽量少改变CANVAS状态
错误代码:
1 2 3 4 | <span> for </span><span>(</span><span> var </span><span>i = </span><span>0</span><span>; i <span>2 </span><span>? COLOR1 : COLOR2);
context.fillRect(i * GAP, </span><span>0</span><span>, GAP, </span><span>480</span><span>);
}
</span></span>
|
Copy after login
正确代码:
1 2 3 4 5 6 7 8 9 | <span>context.fillStyle = COLOR1;
</span><span> for </span><span>(</span><span> var </span><span>i = </span><span>0</span><span>; i <span>2</span><span>; i++) {
context.fillRect((i * </span><span>2</span><span>) * GAP, </span><span>0</span><span>, GAP, </span><span>480</span><span>);
}
context.fillStyle = COLOR2;
</span><span> for </span><span>(</span><span> var </span><span>i = </span><span>0</span><span>; i <span>2</span><span>; i++) {
context.fillRect((i * </span><span>2 </span><span>+ </span><span>1</span><span>) * GAP, </span><span>0</span><span>, GAP, </span><span>480</span><span>);
}
</span></span></span>
|
Copy after login
四.重新渲染的范围尽量小
错误代码:
1 2 | <span>context.fillRect(</span><span>0</span><span>, </span><span>0</span><span>, canvas.width, canvas.height);
</span>
|
Copy after login
正确代码:
1 2 | <span>context.fillRect(</span><span>20</span><span>, </span><span>20</span><span>, </span><span>100</span><span>, </span><span>100</span><span>);
</span>
|
Copy after login
五.复杂场景使用多层画布
1 2 3 4 5 | <span><span>canvas </span><span>width=</span><span> "600" </span><span>height=</span><span> "400" </span><span>style=</span><span> "</span><span>position</span><span>: absolute; </span><span>z-index</span><span>: 0" </span><span>>
</span><span>canvas</span><span>>
<span>canvas </span><span>width=</span><span> "600" </span><span>height=</span><span> "400" </span><span>style=</span><span> "</span><span>position</span><span>: absolute; </span><span>z-index</span><span>: 1" </span><span>>
</span><span>canvas</span><span>>
</span></span></span>
|
Copy after login
六.不要使用阴影
1 2 3 4 5 6 | <span>context.shadowOffsetX = </span><span>5</span><span>;
context.shadowOffsetY = </span><span>5</span><span>;
context.shadowBlur = </span><span>4</span><span>;
context.shadowColor = </span><span> 'rgba(255, 0, 0, 0.5)' </span><span>;
context.fillRect(</span><span>20</span><span>, </span><span>20</span><span>, </span><span>150</span><span>, </span><span>100</span><span>);
</span>
|
Copy after login
七.清除画布
详细性能差别:
http://simonsarris.com/blog/346-how-you-clear-your-canvas-matters
一般情况下:clearRect的性能优于fillRect优于canvas.width = canvas.width;
八.像素级别操作尽量用整数
几种取整数的方法:
1 2 3 4 | <span>rounded = (</span><span>0.5 </span><span>+ somenum) | </span><span>0</span><span>;
</span><span>rounded = ~ ~(</span><span>0.5 </span><span>+ somenum);
</span><span>rounded = (</span><span>0.5 </span><span>+ somenum) <span>0</span><span>;
</span></span>
|
Copy after login
九.使用requestAnimationFrame制作游戏或动画
1 | <p></p><p> (<span> function </span> () {<br> <span> var </span> lastTime = 0;<br> <span> var </span> vendors = [ 'ms' , 'moz' , 'webkit' , 'o' ];<br> <span> for </span> (<span> var </span> x = 0; x window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame' ];<br> window.cancelAnimationFrame =<br> window[vendors[x] + 'CancelAnimationFrame' ] || window[vendors[x] + 'CancelRequestAnimationFrame' ];<br> }<br><br> <span> if </span> (!window.requestAnimationFrame)<br> window.requestAnimationFrame = <span> function </span> (callback, element) {<br> <span> var </span> currTime = <span> new </span> Date ().getTime();<br> <span> var </span> timeToCall = Math.max(0, 16 - (currTime - lastTime));<br> <span> var </span> id = window.setTimeout(<span> function </span> () { callback(currTime + timeToCall); },<br> timeToCall);<br> lastTime = currTime + timeToCall;<br> <span> return </span> id;<br> };<br><br> <span> if </span> (!window.cancelAnimationFrame)<br> window.cancelAnimationFrame = <span> function </span> (id) {<br> clearTimeout(id);<br> };<br> } ());</p>
|
Copy after login
十.其他
与渲染无关的计算交给worker
复杂的计算交给引擎(自己写,或者用开源的),比如3D、物理
缓存load好的图片,canvas上画canvas,而不是画image
同步
本文已同步更新至:
HTML5实验室【目录】: http://www.cnblogs.com/iamzhanglei/archive/2011/11/06/2237870.html