4

I have an application that has about one hundred users. We have a calender view in which every user can have multiple entries. Every entry of the same user should have the same color, but different users should have different colors. At the moment we have manually defined about 25 colors in an array, and the color a user gets is determined by

$color = $colors[$userid % count($colors)];

We don't want to manually add colors for every new user, and selecting a color for each user seems a bit tedious too.

Is there a simple function to map a number (the users id) to a color (preferably RGB)? The next question that rises is; Is there a way to limit the function to a certain types of colors (ie. only colors in which white letters are readable)?

user254875486
  • 11,190
  • 7
  • 36
  • 65

2 Answers2

3

I don't have a solution, per se, but a suggestion.

First, since you want each user's colors to be unique but random, you could get started with some kind of numerical hash function. That gets you a random number that's most likely unique. if your hash function is decent and your users are in the hundreds that should suffice.

Now you need to turn that into colors, preferably on the dark end of the spectrum. If you go with RGB, You need three numbers. To keep them dark, lets say you keep the total or R, G and B under 200. That's a guess, of course, but it should be pretty dark. Pick a random number [index] between 1 and 3 - that's the R, G or B you're going to start with. Get a number between 0 and 200, and set record it for color[index1]. Now pick one of the remaining indexes, 1-3. For this, pick a number between 0 and color[index1] that you already have. Set the remaining number to 200-color[index1]-color[index2]. Now you have a randomish RGB value that should contrast with white.

I realize I never got much use from that hash function up front - maybe ditch it and just use the userid as a random(seed).

Surreal Dreams
  • 26,055
  • 3
  • 46
  • 61
  • I've implemented something like this; I seed the random number generator with the user id, generate a random number between 200 and 300 for the total (R+G+B), then generate 3 random percentages, one for R, one for G and one for B. Scale the percentages so they sum to 100 and assign the corresponding values. Of course, I had to add some additional checks so R, G or B can never be > 255. – user254875486 Apr 24 '12 at 09:02
  • An alternate though on my suggested method could simplify it a fair bit - pick RG&B completely at random, then sum them up and scale the brightness factor back by reducing all three by the same percentage to make the new total fall below some threshold. There's probably a formula out there somewhere to give some kind of readability contrast index - you could do some tests with that to see if the colors are falling into an acceptable range for reading white text. – Surreal Dreams Apr 24 '12 at 15:13
2

You want to work in the hue-saturation-lightness or hue-saturation-value (HSL or HSV) space.

http://en.wikipedia.org/wiki/HSL_and_HSV

Start by defining some colors based on hue and saturation, and set the lightness to the highest tolerable level that makes the text readable.

Then you can fix the hue and saturation for these colors and decrease the lightness.

So say you started by choosing 25 tolerable colors with different hues and maximum/minimum tolerable lightness.

To generate a color for an index you pick the base color to start with base = id % 25 You then decrease the luminance depending on the index within that color index = (Math.floor(id/25)). Set the luminance somewhere within the tolerable luminance range based on that value. So let's say we will have 5 luminance values per color, set the luminance to

lightness = maxLightness - index*(maxLightness / 4*minLightness)

This simply varies the lightness for each color. You can choose to vary saturation and hue slightly if you would prefer. Converting between HSV and RGB is a well documented procedure.

PHP HSV to RGB formula comprehension

Community
  • 1
  • 1
Matt Esch
  • 22,661
  • 8
  • 53
  • 51