Friday, 7 August 2009

Manipulating Colour in Flash - #4 - Building an Interactive Colour Mixer

Now we are beginning to see the end result of all my experiments with manipulating colour using Actionscript. Using the techniques from my previous posts, and a few others to get a working interface, this post explains how to make a simple RGB colour mixer that gives a preview of the colour and the hexadecimal value in a form that can be copy and pasted.

Demo SWF

The Interface

While it is very tempting for those with a graphics background to want to start by designing a groovy interface (including me), it is sometimes a good idea to get just a basic prototype working so you can get the bugs out of the code - and that's what you see here.

The demo above shows my basic interface. Before we can go much further you will need to lay out something similar on your stage. The items in the demo above are labelled, check the key below:


A = MovieClip, instance name 'colourspot_mc'
B = Input Text, instance name 'red_txt', variable 'red'
C = Input Text, instance name 'green_txt', variable 'green'
D = Input Text, instance name 'blue_txt', variable 'blue'
E = Dynamic Text, variable 'displayhex'
F = MoveiClip, instance name 'redpointer_mc'
G = MovieClip, instance name 'redclicker_mc'
H = MoveiClip, instance name 'greenpointer_mc'
I = MovieClip, instance name 'greenclicker_mc'

J = MoveiClip, instance name 'bluepointer_mc'
K = MovieClip, instance name 'blueclicker_mc'

Once you have set up your objects on the stage as above, you are ready to start coding.

The Code

I won't go into long and drawn out explanations of everything this time. The colour manipulation is explained in previous posts on this blog, and other things are explained within the code as comments.

NOTE: For some reason blogger is not treating this code very well. When you dump it into Flash make sure you hit the 'Format' button so it looks as it should.

/* set default values for R, G and B */
var red = 0;
var green = 0;
var blue = 0;
/* Create colour object to control colourspot_mc */
var my_color:Color = new Color(colourspot_mc);
/* Button triggers conversion of RGB into hex, then applies it to the colour object */
onEnterFrame = function() { /*This enables colour to be constantly updated */
/* ensures that only values between 0 and 255 can be used for red */
if (red>255) {
red = 255;
if (red<0) {
red = 0;
/* convert red decimal into hex */
var decred = new Number(red);
hexred = decred.toString(16);
if (decred<=15) {
hexredfinal = "0"+hexred;
} else {
hexredfinal = hexred;
/* ensures that only values between 0 and 255 can be used for green */
if (green>255) {
green = 255;
if (green<0) {
green = 0;
/* convert green decimal into hex */
var decgreen = new Number(green);
hexgreen = decgreen.toString(16);
if (decgreen<=15) {
hexgreenfinal = "0"+hexgreen;
} else {
hexgreenfinal = hexgreen;
/* ensures that only values between 0 and 255 can be used for blue */
if (blue>255) {
blue = 255;
if (blue<0) {
blue = 0;
/* convert blue decimal into hex */
var decblue = new Number(blue);
hexblue = decblue.toString(16);
if (decblue<=15) {
hexbluefinal = "0"+hexblue;
} else {
hexbluefinal = hexblue;
/* build the final 6 digit hex figure and prepend with 0x as needed by Flash */
hex = "0x"+hexredfinal+hexgreenfinal+hexbluefinal;
/* build the final 6 digit hex figure and prepend with # as needed by HTML */
displayhex = "#"+hexredfinal+hexgreenfinal+hexbluefinal;
/* set the colour property of the colour object controlling the MovieClip */
/* Update the location of the pointers */
_root.redpointer_mc._x = ((_root.redclicker_mc._width/256)*red)+_root.redclicker_mc._x;
_root.greenpointer_mc._x = ((_root.greenclicker_mc._width/256)*green)+_root.greenclicker_mc._x;
_root.bluepointer_mc._x = ((_root.blueclicker_mc._width/256)*blue)+_root.blueclicker_mc._x;
/* Set the red decimal value with a clicker */
_root.redclicker_mc.onPress = function () {
redleft = _root.redclicker_mc._x;
clickpos = _xmouse;
clickval = clickpos-redleft;
clickprop = (clickval/_root.redclicker_mc._width)*256;
red = Math.floor(clickprop);
/*moving the pointer
_root.redpointer_mc._x = clickpos;
/* Set the green decimal value with a clicker */
_root.greenclicker_mc.onPress = function () {
redleft = _root.greenclicker_mc._x;
clickpos = _xmouse;
clickval = clickpos-redleft;
clickprop = (clickval/_root.greenclicker_mc._width)*256;
green = Math.floor(clickprop);
/*moving the pointer */
_root.greenpointer_mc._x = clickpos;
/* Set the blue decimal value with a clicker */
_root.blueclicker_mc.onPress = function () {
/*Getting the zero point on the clicker bar */
redleft = _root.blueclicker_mc._x;
/*Capturing the location of the click on the clicker bar */
clickpos = _xmouse;
/*Calculating how far along the clicker bar the click was made */
clickval = clickpos-redleft;
/*Calculating the proportional distance along the bar at which the click was made as a figure between 0 and 1, then converting that into a value between 0 and 256. */
clickprop = (clickval/_root.blueclicker_mc._width)*256;
/*Converting the figure to an integer by rounding DOWN to the nearest whole number. Rounding DOWN ensures we can get 0 at the bottom and 255 rather than 256 at the top. */
blue = Math.floor(clickprop);
/*moving the pointer object to the position clicked on the clicker bar */
_root.bluepointer_mc._x = clickpos;

And there we have it.

Solving Issues as You Go

It is always interesting to solve some issues as you go. For instance, I hadn't quite decided whether I wanted users to be able to type RGB values, or just limit them to using the colour bars.

When I decided that some users might want to be able to type them (as it might be easier and faster in some situations) I realised that some users might enter a value greater than 255 - which would then give inaccurate results. So, at the last minute I included the code that converts any number higher than 255 into 255 and any number lower than 0 into 0. Like I say, always interesting.

Another implication was with the pointers on the colour bars (items F, H and J in my diagram). Making the RGB numbers updatem depending on where the user clicked, and moving the pointers to the place the user clicked was one thing. But now we had to also work it the other way, and get the pointers to move to the place on the colour bar representing the value the user typed. It wasn't difficult, just a case of working the equation the other way, but it needed doing.

Sometimes seemingly small decisions about user experience can have a significant impact on our code. That doesn't mean we shouldn't put the user first, but it does mean we should be prepared to modify our code when needed. After all, our interactive applications need to actually do what the user wants, if we want any users to use them.

No comments:

Post a Comment