Principle
- You take the color values
- You convert the CSS color values into integer
- 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 componentToHex(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 "#" + componentToHex(r) + componentToHex(g) + componentToHex(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.org/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.