I've got what I think is quite an interesting problem that needs an elegant solution...
I have an RGB value, for example 205,50,63
.
I am trying to simulate the colour of an RGB LED on a webpage as if it were REAL-LIFE LIGHT.
For example, the RGB colour 255,0,0
would display as red, both on the LED and on the webpage.
Likewise, the RGB colour 255,255,255
would display as white, both on the LED and on the webpage.
BUT the RGB colour 0,0,0
would display as off on the LED and would be displayed as black on the webpage.
What I am trying to achieve is that both 0,0,0 and 255,255,255 display as white. As if the dimmer the LED is, the whiter it gets.
Ive been trying to apply a proportional algorithm to the values and then layer <div>
over the top of each other with no luck. Any thoughts?
I'm not sure what the case you're imagining is, but reading your desired output, what is wrong with simply scaling up so the maximum value becomes 255?
function scaleUp(rgb) {
let max = Math.max(rgb.r, rgb.g, rgb.b);
if (!max) { // 0 or NaN
return {r: 255, g: 255, b: 255};
}
let factor = 255 / max;
return {
r: factor * rgb.r,
g: factor * rgb.g,
b: factor * rgb.b,
};
}
So you would get results like
scaleUp({r: 0, g: 0, b: 0}); // {r: 255, g: 255, b: 255}
scaleUp({r: 255, g: 0, b: 0}); // {r: 255, g: 0, b: 0}
scaleUp({r: 50, g: 80, b: 66}); // {r: 159.375, g: 255, b: 210.375}
Notice this collapses all {x, 0, 0}
to {255, 0, 0}
, meaning {1, 0, 0}
is vastly different to {1, 1, 1}
. If this is not desirable you'd need to consider special handling of such cases
More RGB hints; you get smoother "more natural" light transitions etc if you square and root around your op, e.g. rather than x + y
, do sqrt(x*x + y*y)
This leads to a different idea of how to solve the problem; adding white and scaling down
function scaleDown(rgb) {
let whiteAdded = {
r: Math.sqrt(255 * 255 + rgb.r * rgb.r),
g: Math.sqrt(255 * 255 + rgb.g * rgb.g),
b: Math.sqrt(255 * 255 + rgb.b * rgb.b)
};
return scaleUp(whiteAdded);
}
This time
scaleDown({r: 0, g: 0, b: 0}); // {r: 255, g: 255, b: 255}
scaleDown({r: 255, g: 0, b: 0}); // {r: 255, g: 180.3122292025696, b: 180.3122292025696}
scaleDown({r: 50, g: 80, b: 66}); // {r: 247.94043129928136, g: 255, b: 251.32479296236951}
and have less of a jump around edge points, e.g.
scaleDown({r: 1, g: 0, b: 0}); // {r: 255, g: 254.99803923830171, b: 254.99803923830171}
Finally, notice this maps rgb onto the the range 180..255
, so you could transform this to 0..255
if you want to preserve your "true red"s etc
function solution(rgb) {
let high = scaleDown(rgb);
return {
r: 3.4 * (high.r - 180),
g: 3.4 * (high.g - 180),
b: 3.4 * (high.b - 180),
};
}
So
solution({r: 255, g: 0, b: 0}); // {r: 255, g: 1.0615792887366295, b: 1.0615792887366295}
solution({r: 1, g: 0, b: 0}); // {r: 255, g: 254.99333341022583, b: 254.99333341022583}
solution({r: 50, g: 80, b: 66}); // {r: 230.9974664175566, g: 255, b: 242.50429607205635}