Jan 2019

HTML Canvas Anti-Aliasing - When Things Don't Line Up

When working with HTML canvas, sometimes you'll find that things don't line up. Sometimes a circle that you draw looks like it fluctuates in size by a few pixels depending on where it is drawn on the canvas. Why is that?

Below you'll see an example of what I mean (canvas has been enlarged to show pixels better):

Look at the edges of the circle as it moves. It appears to very suddenly grow and shrink.

This happens when the x and y coordinates of something drawn on the canvas (be it a path or fill) is a non-integer. In this case, the initial x and y coordinates are integers, but the velocity of the ball is 1.3 pixels per frame. The canvas is doing us a favor by applying anti-aliasing to the circle to give the illusion that we have arbitrary precision x and y coordinates, when in reality we only have integer coordinates. This can be confusing at times when you're creating low resolution images with HTML canvas where you can see this sort of detail. I've ran into this a few times when I make physics simulations with balls that have small borders (1 or 2 pixels) like the one seen above.

Below is how the canvas in your browser applies anti-aliasing to a line of height 1 pixel with decimal offsets:

Look closely (zoom in with your browser). You should see that any line that does not have an integer y coordinate actually has a height of 2 pixels on the canvas. If the line doesn't lie perfectly on a pixel, the intensity is interpolated between the two closest pixels to that coordinate. For example, the 0.5 offset gives both lines half the intensity of the original requested line. This is what it means that the canvas has anti-aliasing, and currently there is no way to completely remove this feature universally in browsers.

While it can't be turned off, if we didn't want this behavior for the simple cases such as these straight lines, we could apply Math.floor or Math.ceil to the final coordinates that we are drawing on the canvas to effectively remove anti-aliasing. But that doesn't handle drawing curves or lines that are not horizontally or vertically parallel to the screen.