I have a value representing the +/-ity of an article which ranges from -1 to 1 with -1 being strongly negative and 1 strongly positive.
I want to turn this into a color such that it ranges from red (strongly negative) pass through grey (neutral) and ends at green (strongly positive).
The solution that I have come up with does not fully satisfy what I am trying to achieve. I am not a color expert but for some reason any value even slightly negative e.g. -.07 is resulting in a bright red. I also expect any positive value to start looking green but what I see is actually orange.
What am I doing wrong? Is there a way to represent what I am after?
function getAsHslHeatMap(value: number) {
value = Math.max(-1, Math.min(1, value));
let hue;
if (value <= 0) {
// Transition from red to grey | Red is 0 degrees
hue = (1 - value) * 0;
} else {
// Transition from grey to green | Green is 120 degrees
hue = value * 120;
}
// Convert hue to an integer for CSS
hue = Math.round(hue);
let saturation = 100; // Full saturation
let lightness = 50; // Mid lightness
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}
There's a couple of simple issues in your code:
0
will always give you 0
(see: hue = (1 - value) * 0;
)120
being green. Therefore, if value
is less-or-equal to 0
you want hue
to to be 0
(red) and if is greater than 0
- set it to 120
(green)red ... gray ... green
involves not only changing hue
, but also saturation. If your value
ranges from -1.0
...0.0
...1.0
that means that in order to define the saturation
to be passed to the HSL — you'll need the absolute (non-negative) float number of value
(times 100
, for percentage)const getAsHslHeatMap = (value) => {
value = Math.max(-1, Math.min(1, value));
const hue = value > 0 ? 120 : 0; // 120 = green; 0 = red
const saturation = Math.abs(value) * 100;
return `hsl(${hue}, ${saturation}%, 50%)`;
};
// DEMO ONLY:
const elInput = document.querySelector("input");
const changeLikeness = () => document.body.style.backgroundColor = getAsHslHeatMap(elInput.valueAsNumber);
elInput.addEventListener("input", changeLikeness); // on input
changeLikeness(); // on init
Likeness: <input type=range min=-1 max=1 value=0 step=0.01>
Or visually:
Negative...|...Positive
value: -1 ....... 0.0 ....... 1
hue: 0 0 120
saturation%: 100 ...... 0 ...... 100