Reputation: 559
I have a lot of elements and mousemove method which, when selecting an item does redraw canvas.
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();
}
}
How to optimize this process, since it runs through all the elements of this highly expensive? May be used async method, but i'm not understand how to apply him?
Upvotes: 1
Views: 1363
Reputation: 9465
Another performance tip: cache your Math.PI * 2 result.
As it is, javascript is getting PI
from an object, then multiplying it. The value is always going to be the same so just add a constant
example
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);
Upvotes: 1
Reputation: 9465
You could also reverse your loop, assuming it's ok to draw everything in reverse order, as jsperf shows this to be quicker. A while loop is even quicker still.
example
var i = nodes.length();
while (i--) {
// ...do stuff...
}
Upvotes: 1
Reputation: 63872
Your calls to save
, restore
and closePath
do nothing as they are written. Remove them.
save
and restore
copy alllll of the canvas state and should be rarely if ever used. In a perfect performant world the only reason you'll ever need to use them is to reset the clipping region.
Draw one and only one path, and fill (and stroke) it only once, at the end.
Like this:
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!
}
Depending on what you're doing its very possible there are more optimizations to be had, but that should help!
Hope your project goes well.
Upvotes: 6
Reputation: 14203
There's a great article on optimizing canvas operations, many of which might apply to you.
Probably the easiest to start with is moving the beginPath()
and closePath()
calls out of your loop, and instead use moveTo()
in between the segments, as well as drawing your canvas off screen and then copying it over to the display canvas.
Upvotes: 2