Color Chooser

Well, here’s my color chooser. I came up with it a little bit ago, and compressed it into an easy-to-use class. It has support for multiple touches, remembers which finger is controlling which part, has a nice little ring for choosing hue, a triangle that spins to your finger in the middle to choose saturation and value, and has a smart little bar on the side to handle alpha. Enjoy!




Color chooser

(Note: the square in the bottom shows you the color you chose and is drawn by Main, and is not actually part of the color chooser class.)

I must admit that I don’t agree with using circles for the colour changer! The correct shape is a hexagon.

@Andrew_Stacey I don’t under stand what you mean. I used a ring to choose hue easily, and it’s used in many other color choosers.

@SkyTheCoder Just because everyone does it doesn’t make it right!

As you go round the colour wheel from red to green, the colour changes as follows:

255,0,0 -> 255,x,0 -> 255,255,0
255,255,0 -> x,255,0 -> 0,255,0

Thus when you consider the RGB cube, what you are actually doing is traversing some of its edges.

Find a cube. Got one? No, I really mean get a cube. Got one now? Good.

Hold it so that one corner is down and the opposite is up. These are black and white respectively. The other corners are the primary and secondary colours, the primary are the lower three and the secondary are the upper three. As you move around the “colour wheel” then you are moving along the edges between these middle corners.

Now look at the cube along the “white - black” axis. What shape do you see outlined?

Circle - schmircle. Hexagons rule.

(By the way, you can see my colour chooser in the Simply Complex app.)

@Andrew_Stacey I honestly can’t find a cube. Any chance you could draw one?

Edit: Another problem is it will take me a bit to think up the vertex geometry for a hexagon (Don’t tell me, I want to think of it myself!). And I have no idea how to make a collision hexagon (for touches.).

@HyroVitalityProtago Ah… I see. Using a circle clips some of the edges a bit. Now for hexagon geometry and collision hexagons… I’ll have to move it to the left a bit, too, as there isn’t any way to put a hole in the middle.

Hey, wait a minute… Doesn’t my ring method work just as a hexagon would? If you look in the code, it essentially takes the edge pixels of the hexagon and stretches them to fit a circle. And then the saturation and value are handles by the triangle, and the bar for the alpha…

Yes, colour choosers work by projecting the hexagon onto the circle. The problem with this is that it gives the wrong “feel” to the user. They think they are smoothly choosing between colours when they are actually doing so in a piecewise linear fashion with “breaks” at the vertices.

One place where the hexagonal method would make a difference is if you implemented a “nearest point” rather than “angle” method for choosing which point on the rim you are selecting.

Try choosing “pure red” with your chooser. Now imagine doing it with a hexagonal chooser that uses the “nearest point” to determine the hue. You have a much bigger target.

Using the hexagon that @HyroVitalityProtago posted, my color chooser is much easier to choose pure red with. Just straight up, the area below the top of the circle is still red, too. Whereas with the hexagon, there’s white in the center, so I would have to make sure I’m choosing the very top of the hexagon to get pure red.

No, you misunderstand. The hexagonal version still uses the border just as the circular one does. What HVP posted was the full RGB cube (projected onto a 2d plane), you don’t use that. You take the boundary and make it thicker, just as with the circle.

Incidentally, selecting a particular line in space is probabilistically as unlikely as selecting a particular point so you’re wrong: you’ve no better chance of selecting pure red with yours as with HVP’s cube.

Does any of this matter if we aren’t building Photoshop, but a simple game for fun?

@Andrew_Stacey I agree with @Ignatz, but I have one last thing to say: when you talked about choosing red, you didn’t say it took the border and expanded it, so I assumed you meant the full hexagon. In that case, It would have been easier using my version. After you explained, yes they are the same. So why are we arguing? But anyways, don’t prove me wrong on something I didn’t post about.

I notice that Sketchbook Pro, a top line drawing app, and iDraw, which some of us use, both have circular colour wheels. Probably, UI design issues were important than technical accuracy, for them.

Looks great. Love it. This should be included in Cider.

@SkyTheCoder Why can’t I prove you wrong about something you didn’t post about? I didn’t read that in the rules! But seriously, I mean no offence and my initial remark was an off-hand one.

Nevertheless, I still think there is a case for a hexagonal chooser and I still want to explain why - I am sort-of a teacher, after all.

Aesthetically, one can say that the circular one looks better and that’s why most UI designers choose it (since when has a UI been designed by function over form?). Moreover, the situation in which it helps is precisely the one where one wants to choose a rough colour and thus not PhotoShop (whatever that might be) that @Ignatz talks about. In a proper drawing program (which I assume PhotoShop to be) then one will want the ability to precisely choose the colour and then no wheel is ever going to give you that ability.

But I’ve lost count of the number of times I’ve tried to select precisely green or precisely blue in the Codea selector and failed miserably. The point is that when choosing a rough colour (that is, say I want “something vaguely orange”) then I can be quite imprecise and so the error on touching a wheel (or hexagon) is not a bother. But even if most of the time I’m happy with an approximate colour, there are times when I want a precise colour and almost always those times are when I want one of the primary, secondary, or black, or white. This is where the hexagon model with the correct selection method triumphs because it allows you to select the primary and secondary colours precisely (black and white come from tinting so are fine in either model).

Note the emphasised phrase.

Here’s how the correct selection method works. You start by touching the (hexagonal) wheel. This signals that you are going to select a hue. The exact hue chosen depends on where you stop touching. But you are allowed to stop touching anywhere on the screen, even off the wheel. Now, how does the code know what colour you meant to choose? The naïve way is to take the line from the centre to the touch point and see where it intersects the wheel. With this method both hexagon and circle give the same answer. But the more sophisticated way is to find the nearest point on the wheel to the touch point. Now it becomes much, much easier to select one of the corners and thus one of the primary or secondary colours.

Let me illustrate with some ascii art. To make this drawable, I have to use a square but the principle is the same.

 | |

In the above, there are nine regions. The middle square represents the colour “wheel”. So when we finish touching the screen, the coordinate returned is the nearest point inside the middle square (or on its boundary if you prefer) to the touch point. The places we’re interested in are the outer regions. If we end up in one of the edge squares then the selected point is simply the corresponding point on the nearest edge. But if we end up in one of the corner squares then the selected point is always the corresponding corner. So it is really, really easy to select a corner as there is a vast region of the screen where you can end up that will guarantee you the corner.

So the hexagonal model is better because not all colours are equal, and the hexagonal model makes it easier to select the colours where it is more likely that you care about them being precise.

Perhaps I should add that while my colour chooser is hexagonal, it still uses the naïve selection method. When I get a minute, I’ll fix that …

@SkyTheCoder this discussion made me intrigated. So i downloaded your code and tried it: that is very nice. Startup is a bit slow, though.
@Andrew_Stacey can you post your code here so i could see the difference? As for theoretical considerations, i though the CIE lab coordinates were the bottom line, and according to them the “good” way to define colors is a triangle of u’ v’ coordinates. Not a circle nor hexagon…

@Andrew_Stacey - I might detect a touch on a circle or a hexagon by drawing it to memory and spriting it, then comparing the touch point with the memory image to get the exact pixel colour.

Your explanation above would make a nice tutorial

Oh botheration! I just deleted a comment that looked like it had been double-posted (by me) and I can’t figure out how to get it back.

Anyway, the gist of it was a reply to @JmV38. Firstly, that CIELAB is a way of specifying a colour, not particularly of choosing it. We’re working in RGB(A) space here since that’s how Codea chooses to handle colours. Once we’re in a model, we can discuss how best to choose a colour but changing models obviously changes how things work.

In RGB space we’re picking a point in a cube. There are various ways to do that, the circular wheel pretends that it is actually a cylinder and wraps that cylinder onto the cube. That obviously introduces breaks. The hexagonal model works a bit better because the breaks are already accounted for.

The difference between triangular and hexagonal is not all that much, it just changes how you go from, say, red to green. Do you go via (255 - t,t,0) or do you first go (255,t,0) and then (t,255,0)? The first is a triangle, the second a hexagon.

My code is freely available in the usual places, and you can use it in the Simply Complex app. But note that I hadn’t thought about the “nearest point” bit until this discussion so it uses the naïve method of using the angle.

@Ignatz That’s what SkyTheCoder’s code does. Isn’t that a bit inefficient? Why not simply compute the angle subtended at the origin. I don’t know, but I think that these get and set methods are not very fast and so I’d always prefer a “pure maths” approach to testing pixels in a sprite.