Avoiding blurry lines when drawing to the canvas

Avoiding blurry lines when drawing to the canvas

Understanding how canvas pixels are rendered


3 min read

If we want to create the best quality images that we can using the Canvas API, we must make sure that they are extremely sharp and in-focus. Blurry lines can ruin an image.

In this article, we will look at the problem of drawing a simple straight line and how without understanding how canvas pixels are rendered, we might accidentally reduce the quality of our image.

To illustrate this issue, we have drawn three lines on a canvas. The two lines on the left have been drawn using lineTo() with lineWidth = 1. The line of the right has been drawn with rect() and has a single pixel width. If we look closely at the three lines, we can see that the first line on the left looks fuzzy compared to the other two lines.

If you want to zoom in and have a look more closely at the difference in how clean these lines are drawn. Go to the styles.css file and add width: 400px under the style border: 1px solid darkorange;. This will force the canvas points to now be drawn at double their default size of 1pt:1px

Why is the first line blurry?

To understand why this is happening, we need to consider how canvas points are drawn. If we look at the grid below, we can see the canvas coordinate system and how this corresponds to the actual pixels used to represent the canvas. We have drawn a single pixel dot at (1,1). From the image you can see that the way this dot has been drawn is that the pixel that represents (1,1) is actually the physical space between coordinates 1 and 2 on both the x axis and the y axis. It is not actually physically possible to draw a dot at exactly (1,1).

Going back to our example, when we draw the line on the right using a rectangle with the commands rect(140,10,1,80) and fill() , we are actually telling the canvas to fill in the space between coordinates 140 & 141. As the space between 140 & 141 is represented by exactly one pixel (when we haven't zoomed in), we are able to draw a clean line.

When we are using stroke() to draw the paths, the canvas will attempt to draw the line at precisely the correct coordinate. In our example, we are drawing the 1st line (on the left) vertically at exactly 60px. But based on how the coordinate system works, there is no real pixel at x = 60 rather the real pixel is between 60 & 61. The canvas will still try to draw a vertical line at exactly x = 60 and the only way it can do this is mathematically shading the pixels either side of the position x = 60 and it is this which causes the line to look fuzzy.

How can we fix the blurry line?

We can solve the blurry line by shifting the line position to x = 59.5. The second (middle) line demonstrates this by using a position of x = 79.5. This position draws a clean line as a 1px wide vertical line positioned at x = 79.5 will use the real pixel between 79 & 80 will not need to shade any surrounding pixels.

Try adjusting the x value of the first line to see how the image can be improved.

I have to put my pen down now. 🤸‍♂️