如何在画布JS上优化绘制很多元素?

时间:2012-09-24 13:16:40

标签: javascript canvas html5-canvas

我有很多元素和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();
    }
}

如何优化这个过程,因为它贯穿了这个非常昂贵的所有元素? 可能会使用异步方法,但我不明白如何应用他?

4 个答案:

答案 0 :(得分:6)

您拨打saverestoreclosePath的电话不会写任何内容。删除它们。

saverestore复制画布状态的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);