javascripthtmlcsscolorslinear-gradients

How can we find out if two colors are similar or not?


So I am trying to change the background of the text as well as the body. I am generating 4 different colors two of which are for the background gradient of the body whereas the other two are for the text.

I calculate a random HEX value using the following code:

  newbg1 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbg2 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbgtext1 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbgtext2 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);

(I apologize for the lack of sensible variable names here)

After this, I perform the following checks to make sure that these are indeed complete 6-digit HEX codes with a "#" preceding them.

if(newbg1.length<7 || newbg2.length<7||newbgtext1.length<7||newbgtext2.length<7)
    onclick();

If any of the generated codes are not of these lengths I call the function itself to generate new hex codes.

However, this is where I encounter a problem. Although the codes are randomly generated, many times it looked like the gradient doesn't exist and it is a solid color. I assumed it is because the same colors are being selected (highly unlikely, but not impossible).

Thus I added another if-statement to check if the colors are the same or not.

if(newbg1 == newbg2 || newbgtext2==newbgtext1 || newbg1 == newbgtext1 || newbg1 == newbgtext2 || newbg2 += newbgtext1 || newbg2 == newbgtext2)
     onclick();

But this still fails to resolve the issue. After a bit trail and error I arrived at the conclusion that the colors are similar and not the same.

I need a method of identifying if 2 given hex values are similar to each other or not and by what degree are they similar. I would also like to know what the minimum difference of 2 hex colors must be so as to obtain a discernable gradient.

I shall also add the complete JS code below:

var bg = document.getElementById("bg");
var inv = document.getElementById("inv");
var textbg = document.getElementById("textbg");

inv.style.opacity="0";
document.body.addEventListener("click", onclick);

function onclick() {
  newbg1 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbg2 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbgtext1 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);
  newbgtext2 = "#" + (Math.random()*0xFFFFFF<<0).toString(16);

  if(newbg1.length<7 || newbg2.length<7||newbgtext1.length<7||newbgtext2.length<7)
    onclick();
  if(newbg1 == newbg2 || newbgtext2==newbgtext1 || newbg1 == newbgtext1 || newbg1 == newbgtext2 || newbg2 == newbgtext1 || newbg2 == newbgtext2)
    onclick();

  inv.style.opacity="1";
  setTimeout(function() {
    bg.style.background = "linear-gradient(-45deg," + newbg1 +"," + newbg2 + ")";
    inv.style.opacity="0";
    bg.style.backgroundSize = "200% 200%";
    bg.style.backgroundRepeat = "no-repeat";
    textbg.style.background = "linear-gradient(-45deg," + newbgtext1 +"," + newbgtext2 + "," + newbgtext1 + ")";
    textbg.style.backgroundSize = "200% 200%";
    textbg.style.backgroundRepeat = "no-repeat";
    textbg.style.webkitBackgroundClip = "text";
    textbg.style.webkitTextFillColor= "transparent";
  }, 500);

}

Solution

  • First, You should use .padStart function, for the case the given number as small (to fill it with leading zeros). like this:

     newbg1 = "#"  + (Math.random()*0xFFFFFF<<0).toString(16).padStart(6, '0');
    

    About check for similarity - You can get the RGB of the colors, and calculate the total distance between each. if it's bigger then some defined value - it's not similar. otherwise - it's similar.

    Something like this:

    (in the following example the total color change to be colled different is 50, but play with it)

    function getRGB(color) {
      color = parseInt(color.substring(1), 16);
      r = color >> 16;
      g = (color - (r<<16)) >> 8;
      b = color - (r<<16) - (g<<8);
      return [r, g, b];
    }
    function isSimilar([r1, g1, b1], [r2, g2, b2]) {
      return Math.abs(r1-r2)+Math.abs(g1-g2)+Math.abs(b1-b2) < 50;
    }
    
    console.log(isSimilar(getRGB('#ffffff'), getRGB('#000000'))) // white and black
    console.log(isSimilar(getRGB('#f10103'), getRGB('#fa1012'))) // to kinds of red