Read my book

I wrote books about Webpack and React. Check them out!

Tuesday, July 27, 2010

HTML5 Canvas Gradients - Linear Gradient Revisited

This time I'm going to revisit linear gradient shown before by providing a version using HTML5 canvas' pixel-wise operations. I will start out by introducing an architecture that makes solving this kind of problems easier and tackle horizontal gradient first. After that I will move to vertical case and finally show how to deal with a linear gradient that has an arbitrary direction.

Horizontal Gradient

As usual I will start out by showing off some code and then chew on it a bit:

The utility libraries the implementation depends upon may be found here: graphics.js, math.js.

I decided to split my architecture in two parts: iterating the pixels and the graphics kernel. This arrangement should make it easy to implement various algorithms even beyond just gradients without too much effort.

As seen above the kernel itself is quite simple. It just performs a linear interpolation (lerp) based on x.

Vertical Gradient

Let's have a look at how vertical gradient works out in this scheme next:

Instead of dealing with the x axis, we just interpolate based on y instead. Not much of change really.

I guess the interesting question now is how to deal with linear gradients with arbitrary directions (ie. from corner to corner). It's going to take some extra math to sort out this case. I will show you how to deal with this case next:

Arbitrary Direction

As seen below the code is a bit trickier in this case:

Though the math may look a bit funky and it might be possible to simplify it further, the basic idea is very simple. First I project the current point to a ray formed by given begin and end points. The projection algorithm will find the point closest to the given point within the ray and return it.

There is one special case to keep in mind. As my projection algorithm deals with a ray, it's possible that the returned vector is not between the bounds. In order to deal with this I perform a check based on normals (normal is a vector that has a length of one unit). If the vectors point to opposite directions the sum of their normals will be zero. This is the case I want to avoid since I want my projection vector to be between or after the bounds.


In this brief post I showed how to generate horizontal, vertical and arbitrary linear gradients using HTML5 canvas API and the pixel-wise operations it offers. I will expand upon the idea in the following posts. It might be nice to revisit radial gradient next and see how that works out.

If you are interested in pixel access I suggest referring particularly to this post by beej for further ideas.