我有很多元素和mousemove方法,当选择项目时会重绘画布。
function redraw(ctx) { // ctx - canvas context
if (!needRedraw)
return;
ctx.save();
ctx.clearRect(0, 0, w, h);
drawItems(ctx);
ctx.restore();
}
function drawItems(ctx) {
var l = nodes.length(); // array of elements for drawing (from 100 to 100000)
for(var i = 0; i < l; i++) {
var item = nodes[i];
ctx.beginPath();
ctx.strokeStyle = colors(item.type);
ctx.fillStyle = fill(item);
ctx.arc(item.x, item.y, item.r, 0, Math.PI * 2, true);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
}
如何优化这个过程,因为它贯穿了这个非常昂贵的所有元素? 可能会使用异步方法,但我不明白如何应用他?
答案 0 :(得分:6)
您拨打save
,restore
和closePath
的电话不会写任何内容。删除它们。
save
和restore
复制画布状态的alllll,如果使用的话应该很少。在一个完美的高性能世界中,你需要使用它们的唯一原因是重置剪裁区域。
绘制一条且只有一条路径,并在最后填充(并描边)一次。
像这样:
function redraw(ctx) { // ctx - canvas context
if (!needRedraw)
return;
ctx.clearRect(0, 0, w, h);
drawItems(ctx);
}
function drawItems(ctx) {
var l = nodes.length(); // array of elements for drawing (from 100 to 100000)
ctx.beginPath(); //outside of loop!
for(var i = 0; i < l; i++) {
var item = nodes[i];
ctx.moveTo(item.x+item.r,item.y); // set up subpath to be at the right point
ctx.arc(item.x, item.y, item.r, 0, Math.PI * 2, true);
}
ctx.fill(); //outside of loop!
ctx.stroke(); //outside of loop!
}
根据您正在做的事情,可能会有更多的优化,但这应该会有所帮助!
希望你的项目顺利进行。
答案 1 :(得分:2)
优化画布操作有great article,其中许多可能适用于你。
最简单的方法可能是将beginPath()
和closePath()
调用移出您的循环,而是在段之间使用moveTo()
,以及在屏幕外绘制画布然后将其复制到显示画布。
答案 2 :(得分:1)
你也可以反转你的循环,假设可以按相反顺序绘制所有内容,因为jsperf显示它更快。一个while循环甚至更快。
示例强>
var i = nodes.length();
while (i--) {
// ...do stuff...
}
答案 3 :(得分:1)
另一个性能提示:缓存您的Math.PI * 2结果。
实际上,javascript从对象获取PI
,然后将其相乘。该值总是相同的,所以只需添加一个常量
示例
const PI_TIMES_TWO = 6.28; //or whatever degree of accuracy you want.
...
ctx.arc(item.x, item.y, item.r, 0, PI_TIMES_TWO, true);