Deomachus
Deomachus

Reputation: 179

Canvas Optimization With rect() And fillRect()

I'm attempting to draw an n-by-n grid of squares where each square consists of layers of colors drawn on top of each other. Drawing the colors to the canvas using fillRect() appears to be working okay and not hemorrhaging any resources. However, when I attempt to add a border around each square using rect(), the performance drops noticeably.

Before each call to the below function, I use clearRect() to clear the canvas.

The function in question:

/**
 * Draws an n x n grid of layered color squares of the given width.
 * @param {int} `width`      The width of each square in the grid.
 * @param {int} `leftOffSet` The left margin of the grid.
 * @param {int} `topOffSet`  The top margin of the grid.
 * @param {int} `n`          The dimension of the grid.
 * @param {object} `layers'  A linked-list of color layers.
 */
function drawMap(width, leftOffSet, topOffSet, n, layers) {
    for (var i = 0; i < n; i++) {
        for (var j = 0; j < n; j++) {

            var currentLayer = layers[i][j];
            while (typeof currentLayer.tile !== 'undefined') {
                var bg = currentLayer.tile.background;

                context.fillStyle = 'rgba(' + bg.r + ',' + bg.g + ',' + bg.b + ',' + bg.a + ')';
                context.fillRect(i * width + leftOffSet, j * width + topOffSet, width, width);

                currentLayer = currentLayer.next;
            }

            // BOTTLE NECK APPEARS TO BE HERE
            /*context.beginPath();
            context.rect(i * width + leftOffSet, j * width + topOffSet, width, width);
            context.stroke();
            context.closePath();*/

        }
    }
}

With the bottle-neck commented out, performance is fine, but as soon as I uncomment that block, the performance drops. Is there any way of optimizing this?

Upvotes: 0

Views: 1220

Answers (1)

markE
markE

Reputation: 105015

Put the context.stroke outside the loop

There's no need to stroke each individual rect as you define it--just context.stroke once at the end.

function drawMap(width, leftOffSet, topOffSet, n, layers) {

    // begin a new path
    context.beginPath();

    for (var i = 0; i < n; i++) {
        for (var j = 0; j < n; j++) {

            var currentLayer = layers[i][j];
            while (typeof currentLayer.tile !== 'undefined') {
                var bg = currentLayer.tile.background;

                context.fillStyle = 'rgba(' + bg.r + ',' + bg.g + ',' + bg.b + ',' + bg.a + ')';
                context.fillRect(i * width + leftOffSet, j * width + topOffSet, width, width);

                currentLayer = currentLayer.next;
            }

            // define new rects,
            //  but don't stroke every new rect
            context.rect(i * width + leftOffSet, j * width + topOffSet, width, width);

            // closePath is not needed if you're just rect-ing
            // context.closePath();


        }
    }

    // all done defining rects, now just do 1 stroke that draws them all
    context.stroke();

}

Upvotes: 1

Related Questions