最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mixing two colors using their hexcodes - Stack Overflow

programmeradmin0浏览0评论

I am making a react native application and am trying to mix two or more colors together using their hexcodes and then getting the resultant color and its hexcode.

For example, where each color has the same proportion, mixing the colors: #4285F4 + #EA4335 + #FBBC05 = #SomeColorHexcode. Is there an algorithm to use in order to get the resulting color's hexcode?

I was looking through some old posts and there seems to be a solution here: Mixing two colors "naturally" in javascript. But the main solution in this post seems to use jquery, which is not supported by react native. Also, this question was asked about 7 years ago and I was wondering if there was a better algorithm available for mixing colors now.

Thanks!

I am making a react native application and am trying to mix two or more colors together using their hexcodes and then getting the resultant color and its hexcode.

For example, where each color has the same proportion, mixing the colors: #4285F4 + #EA4335 + #FBBC05 = #SomeColorHexcode. Is there an algorithm to use in order to get the resulting color's hexcode?

I was looking through some old posts and there seems to be a solution here: Mixing two colors "naturally" in javascript. But the main solution in this post seems to use jquery, which is not supported by react native. Also, this question was asked about 7 years ago and I was wondering if there was a better algorithm available for mixing colors now.

Thanks!

Share Improve this question asked Jun 13, 2020 at 22:12 Questions123Questions123 3742 gold badges7 silver badges20 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

Principle

  1. You take the color values
  2. You convert the CSS color values into integer
  3. You take the middle of each RGB value

let color1 = document.getElementById('color1')
let color2 = document.getElementById('color2')
let colormixed = document.getElementById('colormixed')
let button = document.getElementById('mix')

// this function takes an integer and converts it in a 2 digit hexadecimal number
function ponentToHex(c) {
  var hex = c.toString(16);
  return hex.length == 1 ? "0" + hex : hex;
}

// this function takes an array of 3 RGB integer values and converts this array into a CSS color, like this: #AAAAA
function rgbToHex([r, g, b]) {
  return "#" + ponentToHex(r) + ponentToHex(g) + ponentToHex(b);
}

// the regex is separating the value into groups of 2 characters, these characters being letters from 'a' to 'f' and digits, that is to say hexadecimal numbers. 
function convert(color) {
  return /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color.value).map(x=>parseInt('0x'+x)).slice(1, 4)
}

button.addEventListener("click", function() {
  // we get the two colors and convert them in integer arrays
  let [c1,c2]= [color1,color2].map(x=>convert(x))

  // this variable will be the array of the mixed color
  let cm = []

  // we take the middle of each RGB value between the two colors
  c1.forEach((c,i) => cm.push(parseInt((c1[i]+c2[i])/2)))

  // we convert the value into a CSS value
  colormixed.value = rgbToHex(cm)
});
<input type="color" id="color1" />
<input type="color" id="color2" />
<input type="button" id="mix" value="Mix" /><br />
<input type="color" id="colormixed"/>

The exec is explained here: https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

Short code, several colors

document.getElementById('add').addEventListener("click", function() {
  let newColor = document.createElement("input")
  newColor.type = 'color'
  newColor.className = 'color'
  document.getElementById('colors').appendChild(newColor)
})

document.getElementById('mix').addEventListener("click", function() {
  document.getElementById('colormixed').value = '#'+Array.from(document.getElementsByClassName('color')).map(x=>/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(x.value).map(y=>parseInt('0x'+y)).slice(1, 4)).reduce((a,b)=>a.map( (num, i) => (num + b[i]))).map(x=>parseInt(x/Array.from(document.getElementsByClassName('color')).length).toString(16).padStart(2, '0')).join('')
});
<div id="colors">
  <header>
    <input type="button" id="mix" value="Mix" />
    <input type="button" id="add" value="Add" />
  </header>
  <input type="color" class="color" value="#ffffff" />
  <input type="color" class="color" value="#000000" />
</div>

<label for"colormixed">Result:</label> <input type="color" id="colormixed"/>

Explanation of the one-liner

It takes all the colors:

Array.from(document.getElementsByClassName('color'))

For each element, we take the CSS color code and we separate RGB values:

.map(x=>/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(x.value)

For each element within, we convert every hexadecimal number into an integer:

.map(y=>parseInt('0x'+y))

We take only the RGB triplet:

.slice(1, 4)

We then make the sum of all the RGB arrays:

.reduce((a,b)=>a.map( (num, i) => (num + b[i])))

We divide each RGB summed value by the total number of colors:

.map(x=>parseInt(x/Array.from(document.getElementsByClassName('color')).length)

And we convert back each value to hexadecimal:

.toString(16)

Not forgetting to add a '0' when there is only one digit:

.padStart(2, '0')

We transform the RGB array into a string:

.join('')

And we put the '#' before:

'#' + 

There you have your color mixer.

I believe this code produces the same results as the previous answer, but it's hopefully much clearer how it works.

console.log(mix_hexes('#3890b9', '#f6ff00')); // #8cc46f

function hex2dec(hex) {
  return hex.replace('#', '').match(/.{2}/g).map(n => parseInt(n, 16));
}

function rgb2hex(r, g, b) {
  r = Math.round(r);
  g = Math.round(g);
  b = Math.round(b);
  r = Math.min(r, 255);
  g = Math.min(g, 255);
  b = Math.min(b, 255);
  return '#' + [r, g, b].map(c => c.toString(16).padStart(2, '0')).join('');
}

function rgb2cmyk(r, g, b) {
  let c = 1 - (r / 255);
  let m = 1 - (g / 255);
  let y = 1 - (b / 255);
  let k = Math.min(c, m, y);
  c = (c - k) / (1 - k);
  m = (m - k) / (1 - k);
  y = (y - k) / (1 - k);
  return [c, m, y, k];
}

function cmyk2rgb(c, m, y, k) {
  let r = c * (1 - k) + k;
  let g = m * (1 - k) + k;
  let b = y * (1 - k) + k;
  r = (1 - r) * 255 + .5;
  g = (1 - g) * 255 + .5;
  b = (1 - b) * 255 + .5;
  return [r, g, b];
}


function mix_cmyks(...cmyks) {
  let c = cmyks.map(cmyk => cmyk[0]).reduce((a, b) => a + b, 0) / cmyks.length;
  let m = cmyks.map(cmyk => cmyk[1]).reduce((a, b) => a + b, 0) / cmyks.length;
  let y = cmyks.map(cmyk => cmyk[2]).reduce((a, b) => a + b, 0) / cmyks.length;
  let k = cmyks.map(cmyk => cmyk[3]).reduce((a, b) => a + b, 0) / cmyks.length;
  return [c, m, y, k];
}

function mix_hexes(...hexes) {
  let rgbs = hexes.map(hex => hex2dec(hex)); 
  let cmyks = rgbs.map(rgb => rgb2cmyk(...rgb));
  let mixture_cmyk = mix_cmyks(...cmyks);
  let mixture_rgb = cmyk2rgb(...mixture_cmyk);
  let mixture_hex = rgb2hex(...mixture_rgb);
  return mixture_hex;
}
  • Github Repository

I like @GirkovArpa's answer but there's no need to go to cmyk coloring, and it doesn't support mixing #000000. Here is a function inspired by that answer that mixes two hexes and can optionally accept a mixing ratio.

For javascript, remove type annotations

function hex2dec(hex: string) {
    const matched = hex.replace('#', '').match(/.{2}/g)
    if (!matched) throw new Error('Invalid hex string');
    return matched.map(n => parseInt(n, 16));
}

function rgb2hex(r: number, g: number, b: number) {
    r = Math.round(r);
    g = Math.round(g);
    b = Math.round(b);
    r = Math.min(r, 255);
    g = Math.min(g, 255);
    b = Math.min(b, 255);
    return '#' + [r, g, b].map(c => c.toString(16).padStart(2, '0')).join('');
}

export function mixHexes(hex1: string, hex2: string, ratio: number = 0.5) {
    if (ratio > 1 || ratio < 0) throw new Error('Invalid ratio');
    const [r1, g1, b1] = hex2dec(hex1);
    const [r2, g2, b2] = hex2dec(hex2);
    const r = Math.round(r1 * ratio + r2 * (1 - ratio));
    const g = Math.round(g1 * ratio + g2 * (1 - ratio));
    const b = Math.round(b1 * ratio + b2 * (1 - ratio));
    return rgb2hex(r, g, b);
}

Usage:

console.log(mixHexes('#3890b9', '#f6ff00', 0.7));
发布评论

评论列表(0)

  1. 暂无评论