Using Gradients on HTML5 Canvas

by Patrick Horgan

(Back to canvas tutorials)

You can do subtle and not so subtle stuff

If you see this you have an old browser and this tutorial will be impossible for you to follow.

The term gradients in graphics refers to colors or blacks and greys and whites gradually changing from one place to another.

There's two kinds

As you can see above, there are two different kinds of canvas gradients. There are linear gradients, (the first three examples), and radial gradients, (the next two examples). The last example, which uses the same gradient as the fourth one, shows that gradients can be used for lines as well as for filling.

In the next row, you see what look like buttons. They are just rectangles filled with color with a gradient from opaque white to transparent overlaid on each one.

Linear gradients

Lets look at the gradient used in the first example above. The canvas used in the first example is declared in the html like this

<canvas id='c1' width=100 height=100></canvas>

The gradient used in the first example is declared like this

var grad=ctx.createLinearGradient(0,0,c1.width,c1.height);

It says that the gradient runs from (0,0), the top left corner, to (c1.width,c1.height), the bottom right.

So far it's not useful. We couldn't use it for any filling or stroking because there are no colors associated with it. So we associate colors with it

grad.addColorStop(0,'rgb(0,0,0)'); grad.addColorStop(1,'rgb(255,255,255)');

The first argument can run anywhere from 0 to 1, where 0 means that it applies to the beginning of the gradient, and 1 means that it applies to the end. In this example we used two colors located at the beginning and end, but you can use many colors and you can start after the beginning, and finish before the end. We'll talk more about that in a minute.

In this example, we add colors to the beginning (0) and to the end (1) of the gradient. The beginning will be black, rgb(0,0,0), and the end will be white, rgb(255,255,255).

So all that's left to do is to tell the context that we're going to use the gradient for our fillStyle, and then to fill the canvas with it.

ctx.fillStyle=grad; ctx.fillRect(0,0,c1.width,c1.height);

So how's that 0-1 argument work, anyway?

We're going to draw several gradients in the next diagram, drawn into a canvas with id='zero_one'. They're all going to be specified, like this

var grad=ctx.createLinearGradient(0,0,0,zero_one.height);

That means that the gradient will change linearly from the top to the bottom of the canvas.

The first one is 0.2 - black, 0.6 - yellow, 0.8 - green. That means black from 0.0 to 0.2, changes from black to yellow from 0.2 - 0.6, changes from yellow to green from 0.6 to 0.8, and then is green from 0.8 to 1.0.

grad.addColorStop(.2,'rgb(0,0,0)'); grad.addColorStop(.6,'rgb(255,255,0)'); grad.addColorStop(.8,'rgb(0,255,0)');

I'm just going to say 0.2 - black, 0.6 - yellow, 0.8 - green though.

0.2 - black, 0.6 - yellow, 0.8 - green
0.0 - red, 0.3 - orange, 1.0 - yellow
0.0 - red, 1.0 - yellow
0.0 - black, 0.1 - white, 0.2 - black, 0.3 - white, 0.4 - black, etc.
0.0 - black, 0.08 - grey, .92 - grey, 1.0 - black
0.0 - grey, 0.08 - black, .92 - black, 1.0 - grey
0.0 - red, .167 - orange, .333 - yellow, .5 - green, .667 - blue, .833 - indigo, 1.0 - violet

Same colors, different gradients

The seven previous gradients varied in their colors, but all used a gradient that went from the top to the bottom. In the next examples, well use a simple choice of colors from 0.0 - white, to 1.0 - red. The gradients used, though are as follows, (in order)

var grad=ctx.createLinearGradient(0,0,c7.width,c7.height);
var grad=ctx.createLinearGradient(c8.width,c8.height,0,0);
var grad=ctx.createLinearGradient(0,40,0,60);
var grad=ctx.createLinearGradient(90,10,85,30);
var grad=ctx.createLinearGradient(40,40,30,30);

Lets make a big pretty button

The button is two half circles and a rectangle

canvas=document.getElementById('bb1'); pi=Math.PI; ctx=canvas.getContext('2d'); ctx.beginPath(); ctx.strokeStyle='rgb(0,0,0)'; ctx.arc(30,30,30,pi/2,3*pi/2,false); ctx.stroke(); ctx.strokeRect(30,0,160,60); ctx.beginPath(); ctx.arc(190,30,30,3*pi/2,pi/2,false); ctx.stroke();

We'll draw the button, with a half circle on each side, and a rectangle in the middle.

Fill 'er up!

canvas=document.getElementById('bb2'); pi=Math.PI; ctx=canvas.getContext('2d'); ctx.beginPath(); ctx.fillStyle='rgb(0,128,0)'; ctx.arc(30,30,30,pi/2,3*pi/2,false); ctx.fill(); ctx.fillRect(30,0,160,60); ctx.beginPath(); ctx.arc(190,30,30,3*pi/2,pi/2,false); ctx.fill();

But instead of stroking it, we'll fill it.

Let's start adding gradients

grad=ctx.createRadialGradient(30,30,30,30,30,1); grad.addColorStop(0.0,'rgba(0,0,0,1)'); grad.addColorStop(1.0,'rgba(0,0,0,0)'); ctx.fillStyle=grad; ctx.beginPath(); ctx.arc(30,30,30,pi/2,3*pi/2,false); ctx.closePath(); ctx.fill();

We'll add a radial gradient from opaque black to transparent on the left.

Both ends now

grad=ctx.createRadialGradient(30,30,30,30,30,1); grad.addColorStop(0.0,'rgba(0,0,0,1)'); grad.addColorStop(1.0,'rgba(0,0,0,0)'); ctx.fillStyle=grad; ctx.beginPath(); ctx.arc(30,30,30,pi/2,3*pi/2,false); ctx.closePath(); ctx.fill();

And to the right end.

It looks like anodized aluminum

grad=ctx.createLinearGradient(0,0,0,canvas.height); grad.addColorStop(0.0,'rgba(0,0,0,1)'); grad.addColorStop(0.5,'rgba(0,0,0,0)'); grad.addColorStop(1.0,'rgba(0,0,0,1)'); ctx.fillStyle=grad; ctx.fillRect(30,0,160,60);

And then we make a linear gradient for the middle that goes from opaque black at the top, to transparent in the middle, and then back to opaque black at the bottom.

Now we make it look like reflective glass

grad=ctx.createLinearGradient(0,0,0,canvas.height); grad.addColorStop(0.0,'rgba(255,255,255,1.0)'); grad.addColorStop(1.0,'rgba(255,255,255,0.0)'); ctx.fillStyle=grad; ctx.beginPath(); ctx.arc(30,30,30,pi/2,3*pi/2,false); ctx.lineTo(190,0); ctx.arc(190,30,30,3*pi/2,pi/2,false); ctx.lineTo(30,60); ctx.fill();

And then we make a linear gradient from the top to the bottom from opaque white to transparent on the bottom. That gives a glassy look to the button.

So gradients give you the illusion of curved shape

The bottom line is that gradients are used to make it look like light is shining on a curved surface. If you look at the Game of Life demo page, you'll see some working buttons that use gradients as part of their design. Click on them, hold them down, and see how the illusion is carried forward by using a different gradient when they're clicked, and also by moving the text on them down one pixel. Those buttons are drawn dynamically on the canvas and respond to user input. If you want to see how, look at canvasutilities.js. You can also read about how the events are sent to the buttons. Later I'll make a tutorial about how the buttons work.

(Back to canvas tutorials)