Friday, January 3, 2014

Drawing the colour wheel with JavaScript

A brief follow-up to my earlier post on automatically generating colours using JavaScript, I just couldn't stop! It slightly irritated me that I had to search online for a picture of the colour wheel for the previous article (and found it on Kuler web-site, which is cool and all, but…), while I could easily generate it myself!

So, here's what I came up with, adding some niceties:



This is an example of using a scripting language for quick prototyping and demos, so the approach is not the most efficient performance-wise, but gave me a quick result. The main thing I would change if it were needed for actual usage — I would not use the DOM for individual “pixels”, this is a luxury. Canvas is a better candidate for such things.

The Code

Here's the working example of JSFiddle, and the important snippets are below:
var dim = 51; // Beware of setting too high
var html = '';

for(var i = 0; i < dim; i++) {
    // Draw row
    for(var j = 0; j < dim; j++) {
        // Draw pixel
        html += '<span class="pixel' + (j == 0 ? ' first' : '') 
        + '" style="background-color: ' + getColour(i,j,dim/2) 
        + '"></span>';
    }
}

$('#wheel').append(html);

// Returns colour of pixel based on its offset
//   and circle's radius (square width / 2)
function getColour(i, j, radius) {
    var angle;
    var col = '#fff';
    var x = j - radius;
    var y = radius - i;
    
    var dist = Math.sqrt(x*x + y*y);
    
    // If inside the circle
    if(dist <= radius) {
        angle = Math.round(180 * Math.acos(x / dist) / Math.PI 
           * (y < 0 ? 1 : -1))
           + 90;
        col = 'hsl(' + angle + ', ' 
           + (Math.round(dist / radius * 100)) + '%, ' 
           + (80 - Math.round(dist / radius * 20)) + '%)';
    }
    
    return col;
}

And you need this CSS to have the pixels align correctly:
.pixel {
    display: block;
    float: left;
    height: 6px;
    width: 6px;
    margin: 0 1px 1px 0;
    border-radius: 3px;
}

.first {
    clear: left;
}

Calculations

The logic is simple — remember those trigonometry classes, the ones you couldn't understand why you will ever need them? Why, for drawing colour wheels, of course!

I am drawing a square (wait), and for each pixel from its (x, y) coordinates I detect whether it is within the radius of the circle (see?). If not — draw pixel white (could make it transparent too, if I needed). Distance from the circle origin is the square root of sum of squares of the coordinates. This distance also determines saturation of the resulting colour, and a slight variation of lightness (that makes it look nicer).

The hue is the angle of direction to the pixel compared to the vertical. To determine this I use arccosine — inversion of cosine value (school strikes back). Keep in mind that this gives you result in rads (full circle is two Pi), not degrees, so I still need to convert it.

Put angle and distance together to get a colour — and voila, — you get the nice-looking wheel.

Playing Around

With some time, inspiration and luck there can be many variations of the resulting picture:


…or even the “proper” wheel:



No comments:

Post a Comment