Home > Back-end >  How to find 5-10 colors which are shades away from a given color, which are all visually distinct (i
How to find 5-10 colors which are shades away from a given color, which are all visually distinct (i

Time:12-12

I have a problem where I would like to generate a chart using 5 to 10 variations of 1 primary color, and everything else is a different shade of the main color. The main color is selected by a customer, so this color may be any possible color. It may, for example, be very light, in which case every one of the 5-10 variant colors will be darker than it, or it may be very dark in which case every other variant is lighter than it, or it might be in the middle, so some are darker and some are lighter. It shouldn't matter. Ideally I pass in a given selected color, and it outputs an array of colors which are visually distinct. Something like this:

function getColorPalette(selectedColor, numberOfColorsInOutput = 10) {
  // ?
}

I'm just not sure the best approach of figuring out where in the spectrum the color is, and then how to generate the lighter/darker. colors relative to that. Some trickiness involved there.

const givenColor = '#e6ffe6'

getColorPalette(givenColor, 8).map(buildForDOM).forEach(child => {
  document.querySelector('#generated').appendChild(child)
})

function getColorPalette(selectedColor, numberOfColorsInOutput = 10) {
  const colorObj = tinycolor(selectedColor)
  const n = numberOfColorsInOutput
  const output = new Array(n)
  const fraction = 100 / n
  let i = 0
  while (i < n) {
    output[i] = colorObj.darken(fraction * i).toHex()
    i  
  }
  return output
}

function buildForDOM(color) {
  const div = document.createElement('div')
  div.style.width = '100px'
  div.style.height = '100px'
  div.style.background = `#${color}`;
  return div
}
<script src="https://unpkg.com/[email protected]/tinycolor.js"></script>
<div>Given:</div>
<div style="background: #e6ffe6; width: 100px; height: 100px"></div>
<div id="generated">Generated:</div>

This example code generates a few darker ones, but is incorrect as most of the tail is black. It should fill it in so it fills the spectrum with items as far apart as possible (like CSS justify-content: space-between sort of thing, but for the color output). So it somehow needs to figure out what the hue is or something, and it then generates the shades from that.

It doesn't need to be perfect, anything which generates a spectrum of distinct variations on a given hue will do, that covers the full space of shades (from very light to almost black, but not white and black). It doesn't necessarily even need to contain the selected/given color, just use the hue information from it somehow.

For this implementation I used TinyColor (a JS lib), but you can use that or any other color functionality for darkening/lightening things, doesn't matter to me. Just looking for the hex array at the end.

CodePudding user response:

There are many possible approaches, but here is a very basic solution that uses hsl color in calculations and create an array of different lightness in colors (the levels are based on numberOfColorsInOutput).

It uses the same library and only added some conversion to hsl format (the output is kept as hex, in case it is needed to display on page).

A min and max of lightness can be specified for generated colors, so some control can be set to limit the generation of many darker colors.

If needed, further variations in saturation can be added to the calculation.

Example:

const givenColor = "#FF7F50";
const minLight = 0.1;
const maxLight = 0.9;

getColorPalette(givenColor, 8)
  .map(buildForDOM)
  .forEach((child) => {
    document.querySelector("#generated").appendChild(child);
  });

function getColorPalette(selectedColor, numberOfColorsInOutput = 10) {
  const colorObj = tinycolor(selectedColor);
  const n = numberOfColorsInOutput;
  const output = new Array(n);
  const calcLight = (i) => (i * (maxLight - minLight)) / (n - 1)   minLight;

  let i = 0;
  while (i < n) {
    const baseColor = colorObj.clone().toHsl();
    const outputColor = { ...baseColor, l: calcLight(i) };
    output[i] = tinycolor(outputColor).toHexString();
    i  ;
  }
  return output;
}

function buildForDOM(color) {
  const div = document.createElement("div");
  div.style.width = "100px";
  div.style.height = "100px";
  div.style.background = `${color}`;
  return div;
}
<script src="https://unpkg.com/[email protected]/tinycolor.js"></script>
<div>Given:</div>
<div style="background: #FF7F50; width: 100px; height: 100px"></div>
<div id="generated">Generated:</div>

Hope this will help.

  • Related