2

I have a function that returns a random color. I push these colors into an array. I don't want the colors to be repeated in the array. So I did this:

 $scope.getRandomColor = function getRandomColor(arrayToCheckIfAlreadyContains) {
    var letters = '0123456789ABCDEF';
    var color = '#';
    for (var i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
  //check if array contains the generated color
    if(arrayToCheckIfAlreadyContains.indexOf(color) >= 0){
     let nonRepeatColor = $scope.getRandomColor(arrayToCheckIfAlreadyContains);
     console.log("color repeated", color, arrayToCheckIfAlreadyContains);
     return nonRepeatColor;
    }

    return color;
  }

But I don't know if this is efficient or will even work for sure. Also, it would be great if the colors are distinguishable. Sometimes I get colors that are almost same. How do I make sure that doesn't happen.

Abhi
  • 1,512
  • 2
  • 22
  • 46
  • 1. It's good way to check if it's already in array. 2. When checking if color is in array have some *delta* that indicates min difference between colors – Justinas Mar 08 '19 at 12:25
  • Why don't you use an array or object of distinguishable colors and then pick one of them? – Avanthika Mar 08 '19 at 12:26
  • @Avanthika i dont know how many colors the array needs. it depends on the data from a web service – Abhi Mar 08 '19 at 12:28

3 Answers3

2

hsl can help you produce distinguishable colors. Try this.

function makeColor(colorNum, colors){
    if (colors < 1) colors = 1;
    // defaults to one color - avoid divide by zero
    return colorNum * (360 / colors) % 360;
}
// This could be length of your array.
var totalDIVs = 20;
var totalColors = totalDIVs;

for (var i = 0; i < totalDIVs; i++){
    var element = document.createElement('div');
    document.body.appendChild(element);
    var color = "hsl( " + makeColor(i, totalColors) + ", 100%, 50% )";
    element.style.backgroundColor = color;
    element.innerHTML = color;
}
Avanthika
  • 3,984
  • 1
  • 12
  • 19
1

You might consider using hsl instead of hex notation - pick a number between 0 and 359 for the initial color, then select the other colors such that they're equidistant. For example:

function getColors(num) {
  const initialColor = Math.floor(Math.random() * 360);
  const increment = 360 / num;
  const hsls = [];
  for (let i = 0; i < num; i++) {
    hsls.push(Math.round((initialColor + (i * increment)) % 360));
  }
  return hsls;
}
function displayNew() {
  container.innerHTML = '';
  const hsls = getColors(input.value);
  hsls.forEach((hsl) => {
    const div = container.appendChild(document.createElement('div'));
    div.style.backgroundColor = 'hsl(' + hsl + ', 100%, 50%)';
  });
}
#container > div {
  height: 30px;
}
<input id="input" onkeyup="displayNew()" type="number">
<div id="container"></div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

From your code I don't quite understand what you are doing if the color is already in the array: do you want to pick another random color until you find one color that is not in the array?

Anyways, since your second goal (distinguishable colors), I guess you need some extra work: every time you pick a random color, you need to check its similarity against ALL the colors in the array!

Something like the following:

getRandomColor = function getRandomColor(arrayToCheckIfAlreadyContains) {
    let colorFound = true;        
    let letters = '0123456789ABCDEF';

    do {
        colorFound = true;
        var randomColor = '#';
        for (var i = 0; i < 6; i++) {
            randomColor += letters[Math.floor(Math.random() * 16)];
        }

        arrayToCheckIfAlreadyContains.some(color => {
            if (distanceBetweenColor(color, randomColor) < TRESHOLD) {
                /* Branch taken when randomColor is too similar
                 *  to an already existing color. */
                colorFound = false;
                return true;
            }

            return false;
        });
    } while (!colorFound);
}

Now, how implementing distanceBetweenColor()? You should use Delta-E algorithm: I suggest you to read this answer in SO: https://stackoverflow.com/a/15189004/6070423

EDIT: Notice the use of some instead of forEach: doing this, you stop the iteration as soon as you find a color that is too similar.

Jolly
  • 1,678
  • 2
  • 18
  • 37
  • yes, that's what i was trying to do..call the function until i find a color that isn't in the array. thanks for your anserw – Abhi Mar 08 '19 at 12:55
  • Ok! Then I've edited my code: now, thanks to `do-while` statement, you search random colors until you found one color that can be added to the array. – Jolly Mar 08 '19 at 13:19