Как создать цветовую тепловую карту в JavaScript и CSS?

У меня есть значение, обозначающее +/-ность статьи, которое находится в диапазоне от -1 до 1, где -1 означает строго отрицательный результат, а 1 - строго положительный.

Я хочу превратить это в цвет так, чтобы он варьировался от красного (резко отрицательный) до серого (нейтральный) и заканчивался зеленым (сильно положительный).

Решение, которое я придумал, не полностью удовлетворяет тому, чего я пытаюсь достичь. Я не эксперт по цвету, но по какой-то причине любое значение, даже слегка отрицательное, например. -.07 дает ярко-красный цвет. Я также ожидаю, что любое положительное значение начнет выглядеть зеленым, но на самом деле я вижу оранжевый.

Что я делаю неправильно? Есть ли способ представить то, что мне нужно?

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}%)`;
}

🤔 А знаете ли вы, что...
С помощью JavaScript можно валидировать данные на стороне клиента, что улучшает пользовательский опыт.


1
54
1

Ответ:

Решено

В вашем коде есть пара простых проблем:

  • Умножение на 0 всегда даст 0 (см.: hue = (1 - value) * 0;)
  • Оттенок варьируется от 0 (красный) до 360 (красный), 120 — зеленый. Следовательно, если value меньше или равно 0, вы хотите, чтобы hue было 0 (красный), а если больше 0 - установите его на 120 (зеленый).
  • Движение red ... gray ... green предполагает не только изменение hue, но и насыщение. Если ваш value находится в диапазоне -1.0...0.0...1.0, это означает, что для определения saturation, который будет передан в HSL, вам понадобится абсолютное (неотрицательное) число с плавающей запятой value (умноженное на 100, для процент)

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>

Или визуально:

              Negative...|...Positive
value:       -1 ....... 0.0 ....... 1
hue:               0     0     120
saturation%:  100 ...... 0 ...... 100