For the past couple of years or so, I’ve focused mainly on creating images and animations with Go and my own Go library, blgo, that uses CairoGraphics bindings (my own fork of go-cairo).
When I started creating MiniComps, it was an opportunity to get back into JavaScript-based content creation using HTML’s Canvas and its 2d rendering context. The canvas drawing API is pretty much the same as Cairo, but it’s been nice getting back into interactive, web-based pieces – not so easy in Go/Cairo. I made an updated version of my bitlib library for 2021, bljs, and if you’ve been on this blog or follow me on Twitter, you’ve seen some of the stuff I’ve been doing with it.
But recently I started looking at the documentation for Canvas and the 2d rendering context and found some pretty interesting things that weren’t there last time I looked.
Filters!
This is super powerful. Filters are a cool new way to change the look of your canvas drawings. The context now has a filter
property, which is a string and allows you to add one or more defined filters to it. For example, to add a blur:
context.filter = "blur(8px)";
To add multiple filters, just add them to the string:
context.filter = "blur(8px) contrast(50%) sepia(20%)";
Here’s a demo that allows you to play with a handful of the filters available:
Here are the full list of filters available:
- blur
- brightness
- contrast
- drop-shadow
- grayscale
- hue-rotate
- invert
- opacity
- saturate
- sepia
If you look through these, you’ll realize these are basically the same as already existing CSS filters. In fact, you could already do some of these same affects by adding a filter style to the canvas element itself. For example:
canvas.style = "filter: invert(100%)";
Here’s another demo using this method:
So what’s the difference?
Actually, a pretty big difference. When you apply a filter to a 2d rendering context, it does NOT change the existing content. It will only affect anything drawn after the point when the filter was applied. If you take a look at the code in the first example, I need to clear the canvas and redraw all the content in order to have the filter take place. Whereas applying the filter to the canvas affects the whole element in real time. No need to redraw the content. This also means that using the CSS filter on the canvas element is non-destructive. Using a blur, for example, on the context means the subsequently drawn pixels are permanently blurred.
Also, because the CSS filters apply to the whole element, the blur filter will blur the element beyond its boundaries, whereas the context filter only applies to the pixels inside the canvas. (You can probably change that for the CSS version by applying other styles, such as overflow.)
So far it seems like the CSS version has a lot of the advantages. But the context version does have some plus points. If you want to export the blurred or otherwise filtered image and save it somewhere, you’ll need to have the filters applied to the image in the context, not just the canvas element.
Also, applying filters to the context means you can selectively turn them off and on or change their parameters for each shape you draw. Here’s an example:
Here, the red square is drawn with no filter, the black one with a 10px blur, and the blue with a 0px blur. You couldn’t do that directly with a CSS filter.
Experimental
It’s worth noting that these are experimental features. They may not work in all browsers. Definitely WON’T work as of this writing in Safari or IE, and may change in the future.
SVG Filters
One of the more powerful aspects of being able to use filters is that you are not limited to the fairly basic assortment of built-in filters. You can create extremely complex and powerful filters using SVG and then apply those directly to your canvas context. I’ll discuss how to do that in another article.
Resources
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter