infodev
infodev

Reputation: 5235

Set specific gradient from percentages

I have a code that generates color from values ( from 0 to 200% )

Actually the specter is Green-yellow-red.

I would like to change the gradient to Green-Grey-Red : green if percentage < 100% , grey if in 100% field, red if > 100%.

I don't see how to do it using mathematics formula.

window.onload = function() {
  let colorShower = document.querySelector('.color-shower')
  let colorSlider = document.querySelector('#colorSlider')

  let percentage = (200 -colorSlider.value) /2
  let buildColor = (capHue) => `hsl(${capHue},90%,60%)`
    
  colorShower.style.backgroundColor = buildColor(percentage)
  
  colorSlider.addEventListener('input', e => {
    percentage = (200 -colorSlider.value) /2
    colorShower.style.backgroundColor = buildColor(percentage)
  })
}
.color-shower {
  width: 100%;
  height: 50px;
}

.color-slider {
  width: 100%;
}
<div class = "color-shower"></div>
<input type = "range" min = "1" max = "200" value = "1" class = "color-slider" id = "colorSlider">

Upvotes: 0

Views: 73

Answers (2)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48600

Edit: OK, I updated my response with a dynamic solution. I created wrapper <div> elements around the display/input elements. These wrappers allow you to define both a start-hue and end-hue data attribute. These are used as the gradient start/end for the display.

It's easy to miss (since you have to scroll all the way to the bottom), but with the plugin below; you can call GradientSlider() after your page loads.

The "static" default properties are at the bottom of the function definition. This can easily be re-written into an ES5/6 class.

GradientSlider.defaultOptions = {
  selector : '.gradient-slider'
};

Various sliders are created below. I borrowed Infodev's absolute-value trick to adjust the saturation value as the slider approaches and 50%.

function GradientSlider(options) {
  let opts = Object.assign({}, GradientSlider.defaultOptions, options);

  construct(opts.selector); // Begin...

  function construct(selector) {
    Array.from(document.querySelectorAll(selector))
      .forEach(gradientSlider => initializeSlider(gradientSlider));
  }

  function initializeSlider(gradientSlider) {
    let hueStart = parseInt(gradientSlider.getAttribute('data-start-hue'), 10);
    let hueEnd = parseInt(gradientSlider.getAttribute('data-end-hue'), 10);
    let display = gradientSlider.querySelector('.gradient-slider-display');
    let slider = gradientSlider.querySelector('.gradient-slider-input');
    slider.addEventListener('input', onSliderChange);

    let percentage = getSliderPercentage(slider);
    let hue = percentage < 50 ? hueStart : hueEnd;
    display.style.backgroundColor = calculateColor(hue, percentage);
  }

  function onSliderChange(e) {
    let gradientSlider = e.target.parentElement;
    let hueStart = parseInt(gradientSlider.getAttribute('data-start-hue'), 10);
    let hueEnd = parseInt(gradientSlider.getAttribute('data-end-hue'), 10);
    let display = gradientSlider.querySelector('.gradient-slider-display');
    let percentage = getSliderPercentage(e.target);
    let hue = percentage < 50 ? hueStart : hueEnd;
    display.style.backgroundColor = calculateColor(hue, percentage)
  }

  function calculateColor(hue, percentage) {
    return `hsl(${hue}, ${Math.abs(50 - percentage)}%, 50%)`;
  }

  function getSliderPercentage(slider) {
    let value = parseInt(slider.value, 10);
    let minValue = parseInt(slider.getAttribute('min'), 10);
    let maxValue = parseInt(slider.getAttribute('max'), 10);
    return scaleBetween(value, 0, 100, minValue, maxValue);
  }

  // Source: https://stackoverflow.com/a/60514474/1762224
  function scaleBetween(n, tMin, tMax, sMin, sMax) {
    return (tMax - tMin) * (n - sMin) / (sMax - sMin) + tMin;
  }
}

GradientSlider.defaultOptions = {
  selector : '.gradient-slider'
};

GradientSlider(); // Call the plugin...
.gradient-slider,
.gradient-slider > .gradient-slider-display,
.gradient-slider > .gradient-slider-input {
  width: 100%;
}
.gradient-slider-display {
  height: 50px;
}
<div class="gradient-slider" data-start-hue="120" data-end-hue="0">
  <div class="gradient-slider-display"></div>
  <input class="gradient-slider-input" type="range" min="1" max="200" value="1" />
</div>

<div class="gradient-slider" data-start-hue="240" data-end-hue="300">
  <div class="gradient-slider-display"></div>
  <input class="gradient-slider-input" type="range" min="50" max="150" value="75" />
</div>

<div class="gradient-slider" data-start-hue="30" data-end-hue="180">
  <div class="gradient-slider-display"></div>
  <input class="gradient-slider-input" type="range" min="0" max="10" value="7" />
</div>

Upvotes: 1

infodev
infodev

Reputation: 5235

I have found the solution but it's not perfect

Using this formulahsl(${hue}, ${Math.abs(100 - perc)}%, 50%);

window.onload = function() {
  let colorShower = document.querySelector('.color-shower')
  let colorSlider = document.querySelector('#colorSlider')

  let percentage = (200 -colorSlider.value) /2
  let buildColor = (capHue) => `hsl(${capHue}, ${Math.abs(100 - colorSlider.value)}%, 50%)`
    
  colorShower.style.backgroundColor = buildColor(percentage)
  
  colorSlider.addEventListener('input', e => {
    percentage = (200 -colorSlider.value) /2
    colorShower.style.backgroundColor = buildColor(percentage)
  })
}
.color-shower {
  width: 100%;
  height: 50px;
}

.color-slider {
  width: 100%;
}
<div class = "color-shower"></div>
<input type = "range" min = "1" max = "200" value = "1" class = "color-slider" id = "colorSlider">

But I still have some orange.

Upvotes: 1

Related Questions