Mixing two colors "naturally" in javascript
The RYB Color Model could be a suitable choice for the color mixing calculations. According to Wikipedia, it is primarily used in art and design education, particularly painting.
To mix 2 colors, one converts both colors from RGB to RYB, mixes the colors by adding each color component, and converts the resulting color from RYB back to RGB.
I have tried this using the Online Color Mixing Tool, and the results are
0000FF (blue) mixed with #FFFF00 (yellow) gives #008000 (dark green),
FF0000 (red) mixed with #FFFF00 (yellow) gives #FFA000 (orange).
So this method produces exactly the results that you expected.
Unfortunately, I was not able to find a reference with "ready-to-use" formula to convert from RGB to RYB and back to RGB.
The paper Paint Inspired Color Mixing and Compositing for Visualisation - Gossett and Chen describes the general idea of the RYB color model in the section "2 ACHIEVING INTUITIVE COLOR MIXING".
According to that paper, the conversion from RYB to RGB is done by Trilinear interpolation.
The difficult part is the conversion from RGB to RYB, because it requires the inversion of the trilinear interpolation. See Conversion between RGB and RYB color spaces for more more information.
Even if this answer does not provide complete formula for the calculation, I hope that it gives some ideas how to proceed.
I dedicated 3-4 days to this question. It's a really complex problem.
Here is what you can do if you want to mix two colors "naturally":
CMYK mixing: it's not the perfect solution, but if you need a solution now, and you don't want to spend months with learning about the subject, experimenting and coding, you can check this out: https://github.com/AndreasSoiron/Color_mixer
Implementing the Kubelka-Munk theory. I spent a lot of time reading about it, and trying to understand it. This should be the way to go if you want a professional solution, but it needs 6 parameters (like reflectance, absorption, etc.) for each colors you want to mix. Having R, G, B isn't enough. Implementing the theory isn't hard, but getting those parameters you need about each color seems to be the missing part. If you figure it out how to do it, let me know :)
Experimental: you can do something what the developers of the ipad app: Paper have done. They manually selected 100 pairs of popular colors and eyeball-tested how they should blend. Learn more about it here.
I personally will implement the CMYK mixing for the moment, and maybe later, if I have time I'll try to make something like the guys at Fiftythree. Will see :)
I actually ran into the same issue when trying to mix 2 RGB colors together. These 2 functions worked for me:
//colorChannelA and colorChannelB are ints ranging from 0 to 255
function colorChannelMixer(colorChannelA, colorChannelB, amountToMix){
var channelA = colorChannelA*amountToMix;
var channelB = colorChannelB*(1-amountToMix);
return parseInt(channelA+channelB);
}
//rgbA and rgbB are arrays, amountToMix ranges from 0.0 to 1.0
//example (red): rgbA = [255,0,0]
function colorMixer(rgbA, rgbB, amountToMix){
var r = colorChannelMixer(rgbA[0],rgbB[0],amountToMix);
var g = colorChannelMixer(rgbA[1],rgbB[1],amountToMix);
var b = colorChannelMixer(rgbA[2],rgbB[2],amountToMix);
return "rgb("+r+","+g+","+b+")";
}
To mix red ( [255,0,0] ) with blue ( [0,0,255] ) evenly, you can call
colorMixer([255,0,0], [0,0,255], 0.5);//returns "rgb(127,0,127)" (purple)
This may help, though you have to convert each color value to an array first. If you use Fabric.js to work with canvas elements, this becomes really easy. Just call
var rgbA = new fabric.Color(yourColor);
var rgbB = new fabric.Color(yourSecondColor);
then call
colorMixer(rgbA.getSource(),rgbB.getSource(),0.5);
Hope these functions help.