简体   繁体   中英

Html canvas drawing slows with too many canvas elements

I am working on a slide show editor with a slide-preview strip. I am using electron and react. Each of my slides consists of a background canvas for images/text and a foreground canvas for drawing. My drawing performance is good until I have ~20 slides in my preview strip, then drawing slows down terribly. I am drawing on mouse move event so the user sees it trailing their cursor.

I think I have narrowed down my problem to the ctx.stroke() line when I am drawing on the preview slide. The preview slide is much smaller but has the same resolution as the main canvas the user is actually drawing on.

Is there any way to make this more performant when having >40 canvases on the screen?

apply(ctx, pointIndex) {
    let points = this.path.getPoints().slice(pointIndex);
    ctx.lineWidth = this.getLineWidth();
    if(points.length === 1){
        ctx.fillRect(points[0].x - (this.getLineWidth() / 2), points[0].y - (this.getLineWidth() / 2), this.getLineWidth(), this.getLineWidth());
        return;
    }
    ctx.beginPath();
    ctx.moveTo(Math.floor(points[0].x), Math.floor(points[0].y));
    points.slice(1).forEach(function(point) {
        ctx.lineTo(Math.floor(point.x), Math.floor(point.y));
    });
    ctx.stroke();
    ctx.closePath();
    ctx.lineWidth = 1;
    pointIndex = this.path.getPoints().length - 1;
    return pointIndex;
}

To answer your question: Yes, It takes longer to redraw as you increase the total canvas size. You are dramatically increasing the total canvas size by adding full sized canvases even if those canvases are scaled down to be "slide size". BTW, .stroke is not your problem -- it renders very quickly.

Each of your slide canvases has the same resolution as your main canvas. The DOM must remember the original size so total canvas size increases dramatically with each new slide.

A fix is to make the each slide canvases smaller (== the display size), rather than keeping the same resolution as the main canvas. If the user wants to redraw a slide then dynamically create a full-sized canvas from points for that slide. Less total canvas size == better performance.

Canvas has a scaling command that lets you easily take your full-sized canvas content and scale it to smaller display size:

var c=document.createElement('canvas');
var cctx=c.getContext('2d');
c.width=smallSlideWidth;
c.height=smallSlideHeight;
var scale=Math.min((slideWidth/mainCanvasWidth),(slideHeight/mainCanvasHeight));
cctx.scale(scale,scale);
... now draw your slide using the same coordinates as your main canvas

We don't have more of your code, but if you're redrawing every slide canvas all the time -- don't do that!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM