Slider

by Dominic Myers

HTML

<div class="rangeHolder" data-value="5">
  <div class="legendHolder">
    <div class="legend legend-1">
      <header>1</header>
    </div>
    <div class="legend legend-2">
      <header>2</header>
    </div>
    <div class="legend legend-3">
      <header>3</header>
    </div>
    <div class="legend legend-4">
      <header>4</header>
    </div>
    <div class="legend legend-5">
      <header>5</header>
    </div>
    <div class="legend legend-6">
      <header>6</header>
    </div>
    <div class="legend legend-7">
      <header>7</header>
    </div>
  </div>
  <div class="sliderHolder">
    <div class="arrowPointerBack"></div>
    <div class="arrowPointerFront"></div>
    <div class="pseudoSlider"></div>
  </div>
</div>

SCSS

$range-width: 980px;
$range-height: 100px;
$gradient-position: 70%;
$primary-colour: #2b91de;
$deselected-colour: #7f8c8d;
.rangeHolder {
    position: relative;
    width: $range-width;
    height: $range-width / 7;
    font-family: Arial, Helvetica, sans-serif;
    .legendHolder {
        position: absolute;
        width: $range-width;
        height: $range-height;
        top: 0;
        left: 0;
        display: flex;
        flex-direction: row;
        flex-wrap: nowrap;
        justify-content: flex-start;
        .legend {
            width: $range-width / 7;
            height: $range-height;
            & header{
                cursor: pointer;
                font-size: 1.5em;
                font-weight: bold;
                color: white;
                margin: 5px 0 0 10px;
            }
        }
        @for $i from 1 through 7 {
            .legend-#{$i} {
                background: lighten($primary-colour, percentage(abs(($i - 7) * 5 ) / 100));
                &.deselected {
                    background: lighten($deselected-colour, percentage(abs(($i - 7) * 5 ) / 100));
                    & header{
                        opacity: 0.3;
                    }
                }
            }
        }
    }
    @for $i from 1 through 7 {
        &[data-value="#{$i}"] {
            .sliderHolder {
                left: 140px * $i;
                .pseudoSlider {
                    background: linear-gradient(
                        to right,
                        lighten($primary-colour, percentage(abs(($i - 7) * 5 ) / 100)),
                        lighten($primary-colour, percentage(abs(($i - 7) * 5 ) / 100)) $gradient-position,
                        white $gradient-position,
                        white);
                }
            }
        }
    }
    .sliderHolder {
        position: absolute;
        top: -10px;
        .arrowPointerBack {
            position: absolute;
            height: 20px;
            width: 20px;
   ...

JavaScript

// https://tc39.github.io/ecma262/#sec-array.prototype.find
/* if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    value: function(predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return undefined.
      return undefined;
    },
    configurable: true,
    writable: true
  });
} */

(() => {
  const rangeHolders = document.querySelectorAll(".rangeHolder");
  const triggerChange = (element) => {
    const legends = element.querySelectorAll(".legend");
    const value = parseInt(element.dataset.value, 10) + 1;
    if (!!navigator.userAgent.match(/Trident.*rv\:11\./)) {
      element.classList.add("redraw");
      element.classList.remove("redraw");
    }
    for (let a = 0; a < legends.length; a++) {
      if (parseInt(legends[a].className.split(' ').find(c => /legend-\d/.test(c)).replace(/^\D+/g, ''), 10) < value) {
        legends[a].classList.remove("deselected");
      } else {
       ...