skip to Main Content

I am developing a polling website in which the poll option progress changes color depending on the percentage of votes. Currently, the color changes using an if statement that checks on the progress percentage. Is there a better way to do this without relying on this many if statements? Like a gradient of some sort? I would be okay with both vanilla and jQuery solutions.

function progressColor(progress) {
    if (progress >= 0 && progress <= 24) return '#FFE169';
    else if (progress >= 25 && progress <= 49) return '#FFDE59';
    else if (progress >= 50 && progress <= 74) return '#FF914D';
    else if (progress >= 75 && progress <= 89) return '#FF7A7A';
    else if (progress >= 90 && progress <= 100) return '#FF5757';
}

4

Answers


  1. well, you could use the slightly unusual switch syntax

    progress    = 85;
    
    color       = 'gray';
    switch(true){
      case (progress>=90) : color   = 'blue';     break;
      case (progress>=80) : color   = 'yellow';   break;
    }
    test.style.background    = color;
    div {
       height  : 100px;
    }
    <div id=test></div>

    you dont need the else if since the conditions are mutually exclusive, just seperate if statements will do

    I quite like the if syntax though, it is robust and shows exactly what you are doing

    Login or Signup to reply.
  2. Here’s an approximate parametrization of your color scale.

    You can use the slider to change the background color too.

    function progressColorPara(progress) {
      const progressP = progress / 100;
      const hue = 48 * (1 - progressP);
      const lightness = 71 - 11 * progressP;
      return `hsl(${hue},100%,${lightness}%)`;
    }
    
    for(let i = 0; i < 100; i+=10) {
      const div = document.createElement("div");
      div.style.backgroundColor = progressColorPara(i);
      div.innerText = i;
      document.body.appendChild(div);
    }
    
    document.getElementById("p").addEventListener(
      "input",
      e => document.body.style.backgroundColor = progressColorPara(e.target.valueAsNumber),
    );
    div {
      padding: 0.5em;
    }
    input {
    width: 100%
    }
    <input type="range" min=0 max=100 step=0.1 id=p />
    Login or Signup to reply.
  3. Same function, use math.
    Base color:
    0xFFE169
    final color 0xFF5757
    and between them…0xFFE169 – 0xFF5757 = 8a12
    so:
    every percentage is in hex ~ 162 = (DEC)354

    function progressColor(progress) {
        if(progress == 0) return 'FFE169';
          else {
              return (Number("0x"+"FFE169") - (354 * progress)).toString(16);
                 }
    }
    
    Login or Signup to reply.
  4. To a computer, colour is just a bunch of numbers. That means, in theory, you could do some maths to get the number that’s a certain percentage point difference between a lower and higher number. With your scale, I don’t think it’s as simple as that however we’ll keep the essence of the idea and get some help with a library which does all the complex maths: chroma.js.

    chroma.js has a function called scale which can take an array of colours that appear on the scale. Using the colours in your question, you would build a scale like this:

    const scale = chroma.scale(["#FFE169", "#FFDE59", "#FF914D", "#FF7A7A", "#FF5757"]);
    

    scale returns a function which you can call with a percentage to get the colour at that percentage on the scale.

    scale(0); // #FFE169
    scale(0.25); // #FFDE59
    scale(0.5); // #FF914D
    scale(0.75); // #FF7A7A
    scale(1); // #FF5757
    

    Below is a demo, constructing a scale from the colours in your question and using inputs to change the percentage and get a specific colour on the scale.

    const initialValue = 0;
    const number = document.getElementById("number");
    const range = document.getElementById("range");
    const output = document.getElementById("output");
    const scale = chroma.scale(["#FFE169", "#FFDE59", "#FF914D", "#FF7A7A", "#FF5757"]);
    
    number.value = initialValue;
    range.value = initialValue;
    
    const initialColor = scale(initialValue * 0.01).toString();
    output.style.backgroundColor = initialColor;
    output.textContent = initialColor;
    
    function updateColor(percentage) {
      const color = scale(event.target.value * 0.01).toString();
      output.style.backgroundColor = color;
      output.textContent = color;
    }
    
    number.addEventListener("change", ({ target: { value } }) => {
      range.value = value;
      updateColor(value);
    });
    
    range.addEventListener("input", ({ target: { value } }) => {
      number.value = value;
      updateColor(value)
    });
    body {
      font-family: monospace;
    }
    
    #range {
      width: 100%;
    }
    
    #output {
      align-content: center;
      display: flex;
      flex-direction: column;
      font-size: 24px;
      font-weight: bold;
      height: 50vh;
      justify-content: center;
      text-align: center;
      width: 100vw;
    }
    <input id="number" type="number" min="0" max="100" />
    <input id="range" type="range" min="0" max="100" />
    <output id="output"></output>
    <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.4.2/chroma.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search