Marcos
Marcos

Reputation: 4643

Canvas make the line thicker

Say I have the next code to draw a grid using canvas:

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    rows = 10,
    cols = 10,
    size = canvas.getAttribute("width") / rows;

drawGrid();

function drawGrid() {
    for (var i = 0; i < rows; i++) {
        for (var j = 0; j < cols; j++) {
            ctx.strokeStyle ='rgba(242, 198, 65, 0.1)'; 
            ctx.strokeRect(i * size, j * size, size, size);
            ctx.fillStyle = 'rgb(38,38,38)';
            ctx.fillRect(i * size, j * size, size, size);
       }
   }
}

You can view the result here

My question is why the grid appears thicker if I comment the line ctx.fillRect(i * size, j * size, size, size);

EDIT

And how can I get the same result without using fillRect?

Upvotes: 2

Views: 628

Answers (3)

Simon Sarris
Simon Sarris

Reputation: 63812

your strokes are rendered on half-pixels, which causes them to blur across two pixels. Your fills are covering up part of that, making them look like half pixels again.

The simple solution is to offset the drawing by 0.5, 0.5 in order to draw on whole pixels. For more on this see the section of http://diveintohtml5.info/canvas.html that starts:

Q: Why did you start x and y at 0.5? Why not 0?


Anyway, you shouldn't be using rects for making a grid, you should just be using lines, and you should only ever have to stroke once, at the end, when the grid is done. Doing so ensures that your semi-transparent grid does not have thicker spots at the intersection points of the grid lines.

Here's an example:

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    rows = 10,
    cols = 10,
    size = canvas.width / rows,
    width = canvas.width,
    height = canvas.height;
drawGrid();


function drawGrid() {
    // An odd-sized lineWidth means we should translate to draw on whole pixels
    ctx.translate(0.5, 0.5);
    for (var i = 1; i < rows; i++) {
        ctx.moveTo(0, i * size);
        ctx.lineTo(width, i * size);
    }
    for (var j = 1; j < cols; j++) {
        ctx.moveTo(j * size, 0);
        ctx.lineTo(j * size, height);
    }
    // translate back:
    ctx.translate(-0.5, -0.5);
    // setting stroke style and stroking just once
    ctx.strokeStyle = 'rgba(242, 198, 65, 0.1)';
    ctx.stroke();
}

fiddle: http://jsfiddle.net/tZqZv/4/

Upvotes: 3

Greg Ross
Greg Ross

Reputation: 3498

The rendered strokes are straddling pixel borders. This is manifest in the appearance of what looks like an anti-aliasing effect, and therefore when the fill is not applied and not overlapping the pixel borders, the line appears thicker. If we translate by 0.5, then we do not straddle the pixel borders and observe no difference in the line thickness whether the fill is applied or not. Here's an example.

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    rows = 10,
    cols = 10,
    size = canvas.getAttribute("width") / rows - 5;
drawGrid();


function drawGrid() {
    for (var i = 0; i < rows; i++) {
        for (var j = 0; j < cols; j++) {
            ctx.strokeStyle ='rgba(0, 0, 0, 1)';
            ctx.strokeRect(i * size + 0.5, j * size + 0.5, size, size);
            ctx.fillStyle = 'rgb(38,128,128)';
            //ctx.fillRect(i * size + 0.5, j * size + 0.5, size, size);
        }
    }
}

Here's a decent reference to the effect.

Upvotes: 2

Matt Burland
Matt Burland

Reputation: 45135

Because your fillRect is overlapping with the borders drawn by strokeRect.

Upvotes: 1

Related Questions