Question

Is it possible to greate a linear gradient which contains all possible RGB colors (only red, green, blue - no alpha values) for a linear color picker.

So far I've tried it with the following gradient, but it doesn't contain all values from rgb(0,0,0) to rgb(255,255,255) :

var grd = ctx.createLinearGradient(0, 0, width, 0);
grd.addColorStop(0,     'red');
grd.addColorStop(1 / 6, 'orange');
grd.addColorStop(2 / 6, 'yellow');
grd.addColorStop(3 / 6, 'green')
grd.addColorStop(4 / 6, 'aqua');
grd.addColorStop(5 / 6, 'blue');
grd.addColorStop(1,     'purple');

Any help is highly appreciated.

Was it helpful?

Solution

Unfortunately no you can't.

The main reason is that 24-bit RGB contains 16,777,216 number of colors (2563). Just to get an estimate you will will need a screen resolution that is 4096 x 4096 pixels (of course there is no such square screen, but the equivalent would be in about 16:9 format of that for an actual monitor).

Simply put: there is no room to place all the pixels on a normal screen.

In addition you will get problem using a gradient as this goes only in one direction for canvas. You would need to plot the color in two directions which you need to do manually manipulating the bitmap directly.

My suggestion is to take a screen snapshot of an existing such palette and draw that image onto the canvas. This will quantize the colors (this also happens in all available color pickers) but will give you a close approximation to the color you need.

In addition you can add sliders to fine-adjust the value as well as text boxes (the latter is a bit complicated in pure canvas, but you can make a combination of html and canvas to achieve this).

An approximation representing "all" colors could be like this (snapshot from demo below):

Snapshot from demo below

Update

Ok, I promised to get back to you about calculating the position from a RGB value. Starting in a palette as in the image you can easily calculate the position by converting the color to HSV color space.

The function to do RGB to HSV looks like this:

function rgb2hsv() {

    var rr, gg, bb,

    r = arguments[0] / 255,
    g = arguments[1] / 255,
    b = arguments[2] / 255,
    h, s,

    v = Math.max(r, g, b),
    diff = v - Math.min(r, g, b),
    diffc = function (c) {
        return (v - c) / 6 / diff + 1 / 2;
    };

    if (diff === 0) {
        h = s = 0;

    } else {
        s = diff / v;

        rr = diffc(r);
        gg = diffc(g);
        bb = diffc(b);

        if (r === v) {h = bb - gg}
        else if (g === v) {h = (1 / 3) + rr - bb} 
        else if (b === v) {h = (2 / 3) + gg - rr};
        if (h < 0) {h += 1}
        else if (h > 1) {h -= 1}
    }

    return {
        h: (h * 360 + 0.5) |0,
        s: (s * 100 + 0.5) |0,
        v: (v * 100 + 0.5) |0
    }
};

Now color is represented in degrees (0-359), saturation (0-100) and luminance (0-100).

To get horizontal position all you need to do is to divide width of your palette on 360 and multiply with h (hue). To get vertical position you split the palette in upper part and lower part. If saturation is < 100 then you're in the upper part, if V < 100 then you're in lower part:

function getPos(canvas, h, s, v) {

var m = canvas.height / 2,
    x = canvas.width / 360 * h,
    y;

if (s === 100 && v === 100) {
    y = m;

} else if (v === 100 && s < 100) {
    y = m / 100 * s;

} else if (s === 100 && v < 100) {
    y = m / 100 * (100 - v) + m;
}

x = (x + 0.5) |0; //convert to integer
y = (y + 0.5) |0;

};

This will of course require that the palette you generate is very accurate.

Demo

Notice the cursor is not set based on mouse position, but on RGB (HSV) value. It first picks a color RGB from mouse position, then converts it to HSV and calculate the position from that.

The palette is generated dynamically in relation to window size.

Also worth to mention for plain color picking, is that the problem with gradients that seems smooth is that they are dithered. This means that you can get a pixel value that apparently is not in the range you're picking from.

To reduce this problem when you do a color pick, you will need to average the area around the x and y position you get from the mouse.

OTHER TIPS

You may want to ask yourself what do you want to do with these colors, and why. Also, you might consider the kind of users you will have and what they will want to do with the colors.

As the other responders have noted, the RGB color space is 3-dimensional. But there is more than one way of mapping those three dimensions. There is also Hue/Saturation/Value (HSV). Many applications with color pickers have both, side by side or in separate tabs.

Hue, the H in HSV, can be thought of as position along the rainbow, starting at red #ff0000 and cycling back to red again. This is often represented as a position along a circle, with red at 0 degrees/ 360 degrees, green #00ff00 at 120 degrees and blue #0000ff at 240.

Saturation refers to "how much color is in the color", with 100% saturation being the full color and 0% saturation representing monochrome black, white and grey. Value represents how bright or dark the color is, with 0% value being black #000000 for any hue, and 100% being full brightness, which will be the full color for that hue if the saturation is also 100%.

Here is a screenshot of the Gimp color picker. You can see that it has sliders for Hue, Saturation and Value above the sliders for Red, Green and Blue.

Gimp color picker

The values for Hue range from 0 to 359 degrees, Saturation and Value range from 0% to 100%, and Red, Green and Blue from 0 to 255 (ff in hexadecimal). The triangle rotates around the rainbow - the Hue values - and the inside of the triangle displays the 2-dimensional Saturation - Value color space for that particular hue. You can play and experiment with all these variables and learn how RGB and HSV values relate to each other.

Depending on your application, you might want to take a look at the traditional "web safe colors". These were more important in the early days of the Web when everything was new, browser compatibility issues were prevalent and web pages were viewed on CRT screen monitors. The "web safe" colors had the best chance of looking consistent on different screens from different vendors. Even though this is not important anymore, they still make a good starting point for colors on almost any computer application, from which you can diverge as desired.

The "web safe" colors are the set of colors generated by using multiples of 17 for the RGB values, with special emphasis on multiples of 51 (3 x 17).

Why 17? Because 11 in hexadecimal is equal to 16 plus 1, or 17 in decimal notation. 255, which is 2 to the 8th power minus 1, is 15 times 17, or ff in hexadecimal digits. This makes the values of 0%, 20%, 40%, 60%, 80% and 100% fit nicely into 0, 51, 102, 153, 204 and 255, which is written neatly in hexadecimal notation as 00, 33, 66, 99, cc, and ff.

+1 Philipp is spot on. RGB colors are not well represented in 2d space because rgb has 3 components that all must be represented.

The closest you can get to geometrically representing all rgb combinations is a cube (makes sense since a cube has 3 axes and rgb has 3 values).

Here's an illustration from Wikipedia: http://en.wikipedia.org/wiki/RGB_color_space

enter image description here

You could use this as a starting place and use a slider to show each color "layer" from front to back.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top