This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Canvas Effects

7:14 JavaScript lesson by

Learn some of the different ways you can affect the graphical content that you are drawing to a canvas. We'll cover global alpha, global composite operations and shadows.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Learn some of the different ways you can affect the graphical content that you are drawing to a canvas. We'll cover global alpha, global composite operations and shadows.

By default, when you draw any content to a canvas, that content is drawn directly over any previously existing content, covering and obliterating it. There are a few different effects you can apply that will change how this new content interacts with what's already there.

The first and simplest of these is called global alpha. This is simply a number from 0 to 1 that affects the opacity of all future content drawn to the canvas. It's simply a property on the 2D rendering context. Setting it doesn't affect any existing content, but will affect whatever is drawn after that point. This allows new content to blend with existing content, rather than simply overwrite it.

Here, I'll set the fill color to red and draw a rectangle. Then I'll set it to blue and draw another overlapping rectangle. Obviously the newer blue rectangle is drawn on top of the red one. If I set context.globalpha to 0.5 before drawing the blue rectangle, you see that it's drawn with 50 percent opacity, so you can see the red shape beneath it.

If I move the global alpha line up here, then the red rectangle is also drawn with 50 percent opacity. I can change that lower to around 0.1, and you can barely even see either rectangle. After drawing one rectangle I can set global alpha back to 1 and the blue rectangle is drawn normally. Although this is the simplest method for this purpose, as you can see, it can be very useful.

If you need a bit more control over how new content blends with old, then global composite operation is what you're looking for. Although that sounds like a complex, scary name, just think of blending modes in a graphics application like Photoshop.

The global composite operation types are exactly the same concept, and in fact many of them have the same names and do the same things as blending modes in Photoshop.

Here's a list of all possible operations. These are all strings that are simply assigned to the context.globalcompositeoperation property. Like most other properties in the canvas API, this doesn't affect any existing content on the canvas, but will change how future content is drawn.

For the sake of this discussion, the source image is the new content you're drawing to the canvas, and the destination image refers to the existing content already in the canvas. The default composite operating is the string source over. As we just said, this draws the source image over the top of the destination image.

The opposite of this is destination over. This results in the source image behind drawn under the destination image. This can be very useful if you want to layer bunch of objects front-to-back, instead of the usual back-to-front.

Then there are a few operations that have in-out-in-atop in their names. These can be used to make various types of masks our cutouts with different shapes, as well as other effects. For example, if we use source out, this removes the destination image and draws the source image only where it falls outside of that destination image.

Note that the red rectangle is one, and the blue one has a space in it where the red rectangle was. With source in, the red rectangle is still gone, but the blue one is only drawn where it was inside the original destination image.

There are also destination versions which do the opposite. With destination in, only a bit of the original red rectangle remains, where it is within the blue rectangle. With destination out, only the red rectangle remains, with a space where the blue one would be.

In these versions, the source image only affects what remains in the destination image. It doesn't actually get drawn itself.

Then there's source atop. This is about the same as source in, but it leaves the original content there. Destination atop is about the same as destination in, but the new content is drawn.

One that I use more often than many others is xor. This is based on the Boolean exclusive or operation. Here, a pixel is drawn if it is in the source image or in the destination image, but not if it's in both.

Most of the rest of the operations rely on more complex operations between pixel values. The simplest are lighten, which keeps the lightest pixel value in both images, or darken, which keeps the darkest values.

The rest require more complex images than flat rectangles of solid colors to really see what they're doing. I suggest going to this page at the Mozilla develop network, which shows examples of each one and gives you a live playground app to experiment with. Understanding all these operations will give you a lot of power to make complex graphics using code.

The final effect we'll look at here is shadows. Personally, I'm a bit baffled with how Spartan the canvas drawing API is in general, and the fact that there is no kind of blur or other filter API. We get something as gratuitous as drop shadows. That's what we're given, so let's take a look.

Creating shadows requires setting four properties in the context. These are shadow color, shadow blur, shadow offset x, and shadow offset y. Minimally you'll need to specify the color and blur, but it's best to set all of them.

Here I've left the red rectangle and applied a black shadow color and a 10-pixel blur. You can just see the shadow around the edges of the shape. Setting the shadow offset x and y moves the shadow about how you'd expect it to.

Now that we have more of the shadow in view, maybe it looks a bit dark. This is usually the case if you're using straight black as a shadow color. Try using the RGBA method of defining colors to give it a little less opacity. 50 percent alpha makes it look a lot better. That's about all there really is to shadows. If you make some of these values dynamic, you can come up with some pretty cool effects.

Here, I'll leave the shadow color and replace the rest with the mouse move event handler. In that handler function I'll clear the canvas, calculate the distance from the mouse to the center of the canvas on the x-axis and y-axis, and the total distance using math square root.

I'll set shadow offset x to about half that x distance, and shadow offset y to half the y distance. Then I'll set shadow blur to a fraction of the overall distance. Finally I'll just set the fill style to red and draw a rectangle extending 100 pixels between the center in any direction.

Because the shadow offsets are set to the distance from the mouse to the center of the rectangle, it has the effect of making the mouse seem like a light source, casting this shadow in the opposite direction. The fact that the blur increases with the distance adds to that effect. Of course, this is a rather quick and crude implementation, but it gives you an idea of what can be done with this feature.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?