Cara Membuat Slider Range Equalizer Responsive



Slider Range Equalizer Responsive adalah Slider yang berbentuk Equalizer yaitu salah satu alat music yang mengatur kenyaringan frekuensi suara. Namun pada postingan ini kita tidak akan membahas tentang Equalizer music melainkan Equalizer Progress Skill yang bisa kita pasang pada blog.

Slider Range Equalizer sama seperti Widget Progress Skill yang berfungsi untuk memperlihatkan hasil dari suatu kegiatan yang dilakukan selama pekerjaan itu berlangsung. Bagaimana cara pemasangannya? sobat bisa ikuti tutorial di bawah ini.., Namun sebelum kita melanjutkannya, sobat bisa lihat dulu tampilannya pada link preview di bawah.

DEMO

Sudah lihat penampakannya? kalau sudah ikuti caranya berikut ini...

<style>
.component {
  position: relative;
  color: white;
  background-color: #3D3D4A;
  border-radius: 10px;
  box-shadow: 0px 20px 40px rgba(0, 0, 0, 0.5), 0px -2px 40px rgba(0, 0, 0, 0.3);
  min-width: 280px;
  display: -webkit-box;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
          flex-direction: column;
}
.component:before, .component:after {
  content: '';
  background-color: transparent;
  position: absolute;
  z-index: -1;
  box-shadow: 0 20px 20px rgba(0, 0, 0, 0.3);
  top: 100%;
  bottom: -5px;
  left: 8%;
  right: 8%;
  border-radius: 50%;
}
.component:after {
  box-shadow: 0 25px 20px rgba(0, 0, 0, 0.6);
  left: 12%;
  right: 12%;
}
.component aside {
  position: relative;
  display: block;
  background: #373641;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
}
.component aside .preamp {
  height: 70px;
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
          justify-content: center;
  -webkit-box-align: center;
          align-items: center;
}
.component aside .preamp > label {
  color: #DEDFE4;
  text-transform: uppercase;
  display: block;
  font-weight: 700;
}
.component .main_post {
  position: relative;
  display: block;
  padding-bottom: 50px;
}
.component .main_post .presets {
  display: -webkit-box;
  display: flex;
  -webkit-box-align: center;
          align-items: center;
  -webkit-box-pack: center;
          justify-content: center;
  padding: 10px;
  padding-left: calc(40px/2 - .5em);
  height: 100px;
  color: #8e8e9b;
  font-weight: 700;
  border-color: #4F4F62;
  background: transparent;
}
.component .main_post .presets > label {
  display: inline-block;
  margin-right: 20px;
}
.component .main_post .presets > select {
  -webkit-appearance: none;
  border-radius: 8px;
  border: 2px solid currentColor;
  max-width: 200px;
  padding: 4px;
  color: inherit;
  background: transparent;
  border-color: inherit;
  height: 30px;
  margin-right: 10px;
}

.component .main_post .presets > select option {
  background-color: #3D3D4A;
}
.component .main_post .presets > button {
  height: 30px;
  border-radius: 8px;
  background: transparent;
  color: inherit;
  border: 2px solid currentColor;
  border-color: inherit;
  padding: 4px 10px;
  cursor: pointer;
  outline: none;
}
.component .main_post .sliders {
  position: relative;
  display: inline-block;
}
.component .main_post .sliders .range-slider {
  display: inline-block;
  width: 40px;
  position: relative;
  height: 300px;
  float: left;
}
.component .main_post .sliders .range-slider::after {
  position: absolute;
  bottom: -24px;
  left: calc(50% - 2em);
  font-size: 80%;
  color: #8e8e9b;
  content: '32';
  width: 4em;
  text-align: center;
}
.component .main_post .sliders .range-slider:nth-child(2)::after {
  content: '32';
}
.component .main_post .sliders .range-slider:nth-child(3)::after {
  content: '64';
}
.component .main_post .sliders .range-slider:nth-child(4)::after {
  content: '128';
}
.component .main_post .sliders .range-slider:nth-child(5)::after {
  content: '256';
}
.component .main_post .sliders .range-slider:nth-child(6)::after {
  content: '512';
}
.component .main_post .sliders .range-slider:nth-child(7)::after {
  content: '1K';
}
.component .main_post .sliders .range-slider:nth-child(8)::after {
  content: '2K';
}
.component .main_post .sliders .range-slider__thumb {
  opacity: 1;
  position: absolute;
  left: 10px;
  width: 20px;
  height: 20px;
  line-height: 20px;
  background-color: white;
  color: #8376FF;
  text-align: center;
  font-size: 40%;
  box-shadow: 0 0 2px #373641;
  border-radius: 50%;
  pointer-events: none;
  cursor: pointer;
  z-index: 2;
}
.component .main_post .sliders .range-slider__bar {
    left: 18px;
    bottom: 0;
    position: absolute;
    background: -webkit-gradient(linear, left top, left bottom, from(#f75017), to(#ff8100));
    background: linear-gradient(#f75017, #ff8100);
    pointer-events: none;
    width: 4px;
    border-radius: 10px;
    opacity: 1;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical] {
  position: relative;
  margin: 0;
  height: 100%;
  width: 100%;
  display: inline-block;
  position: relative;
  -webkit-writing-mode: bt-lr;
      -ms-writing-mode: bt-lr;
          writing-mode: bt-lr;
  -webkit-appearance: slider-vertical;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-webkit-slider-runnable-track, .component .main_post .sliders .range-slider input[type=range][orient=vertical]::-webkit-slider-thumb {
  -webkit-appearance: none;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-webkit-slider-runnable-track {
  border: none;
  background: #343440;
  width: 4px;
  border-color: #343440;
  border-radius: 10px;
  box-shadow: 0 0 0 2px #3D3D4A;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-moz-range-track {
  border: none;
  background: #343440;
  width: 4px;
  border-color: #343440;
  border-radius: 10px;
  box-shadow: 0 0 0 2px #3D3D4A;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-ms-track {
  border: none;
  background: #343440;
  width: 4px;
  border-color: #343440;
  border-radius: 10px;
  box-shadow: 0 0 0 2px #3D3D4A;
  color: transparent;
  height: 100%;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-ms-fill-lower, .component .main_post .sliders .range-slider input[type=range][orient=vertical]::-ms-fill-upper, .component .main_post .sliders .range-slider input[type=range][orient=vertical]::-ms-tooltip {
  display: none;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-webkit-slider-thumb {
  left: -20px;
  position: relative;
  width: 40px;
  height: 40px;
  opacity: 0;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-moz-range-thumb {
  position: relative;
  width: 40px;
  height: 40px;
  opacity: 0;
}
.component .main_post .sliders .range-slider input[type=range][orient=vertical]::-ms-thumb {
  position: relative;
  width: 40px;
  height: 40px;
  opacity: 0;
}
.component .main_post .sliders svg {
  z-index: 1;
  overflow: visible;
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke-width: 1;
}
.component .main_post .sliders svg .line {
  stroke: #fbe921;
}
.component .main_post .sliders svg .line-shadow {
  z-index: 1;
  stroke-width: 2;
  stroke: #252525;
  opacity: .35;
  display: none;
}
.design-reference {
  position: fixed;
  bottom: 6px;
  right: 6px;
  color: #8e8e9b;
  font-size: 70%;
  display: none;
}
@media (min-width: 800px) {
  .component {
    -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
            flex-direction: row;
  }
  .component .main_post .presets > select {
    min-width: 200px;
    padding-left: 10px;
  }
  .component .main_post .presets {
    padding-left: calc(80px/2 - .5em);
    -webkit-box-pack: start;
            justify-content: flex-start;
  }
  .component aside .preamp {
    height: 100px;
  }
  .component .main_post .sliders svg .line-shadow {
    display: block;
  }
  .component aside {
    border-top-right-radius: 0;
    border-bottom-left-radius: 10px;
    min-width: 140px;
  }
  .component .main_post {
    padding-left: 20px;
    padding-right: 20px;
  }
  .component .main_post .presets > button {
    min-width: 80px;
  }
  .component .main_post .sliders .range-slider {
    width: 80px;
  }
  .component .main_post .sliders .range-slider__thumb {
    left: 30px;
  }
  .component .main_post .sliders .range-slider__bar {
    left: 38px;
  }
}
@media (min-height: 600px) {
  .design-reference {
    display: block;
  }
}
</style>


<div class="component">
<aside>
<div class="preamp">
<label>preamp</label>
</div>
</aside>
<div class="main_post">
<div class="presets">
<label>Presets:</label>
<select name="Custom" onchange="app.selectPreset(this)">
<option value="custom">Custom</option>
<option value="rock">Rock</option>
<option value="pop">Pop</option>
<option value="pop">Classical</option>
<option value="pop">Disco</option>
</select>
<button class="reset" onclick="app.reset()">Reset</button>
</div>
<div class="sliders">
<svg preserveAspectRatio="none" viewBox="0 0 140 100">
<path d="" class="line-shadow"></path>
<path d="" class="line"></path>
</svg>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
<div class="range-slider">
<input type="range" orient="vertical" min="0" max="100" />
<div class="range-slider__bar"></div>
<div class="range-slider__thumb"></div>
</div>
</div>
</div>
</div>

<script> 
//<![CDATA[
// String formatter
if (!String.prototype.format) {
  String.prototype.format = function () {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function (match, number) {
      return typeof args[number] != 'undefined' ? args[number] : match;
    });
  };
}

let app = (() => {

  const $svgLine = document.querySelector('svg .line');
  const $svgLineShadow = document.querySelector('svg .line-shadow');
  const sliderThumbSize = 20;
  const sliderHeight = 300;
  const svgViewBoxHeight = 100;
  const svgViewBoxThumbLimit = sliderThumbSize / 2 * (svgViewBoxHeight / sliderHeight);
  const svgViewBoxGraphMax = svgViewBoxHeight - svgViewBoxThumbLimit;
  const svgViewBoxGraphMin = svgViewBoxThumbLimit;

  let ranges = {
    range1: null,
    range2: null,
    range3: null,
    range4: null,
    range5: null,
    range6: null,
    range7: null };

  // Only the y values changes
  let points = {
    begin: {
      x: 10,
      y: 0 },

    point1: {
      x: 10,
      y: 0 },

    control1: {
      x: 20,
      y: 10 },

    control2: {
      x: 20,
      y: 0 },

    point2: {
      x: 30,
      y: 0 },

    control3: {
      x: 40,
      y: 0 },

    point3: {
      x: 50,
      y: 0 },

    control4: {
      x: 60,
      y: 0 },

    point4: {
      x: 70,
      y: 0 },

    control5: {
      x: 80,
      y: 0 },

    point5: {
      x: 90,
      y: 0 },

    control6: {
      x: 100,
      y: 0 },

    point6: {
      x: 110,
      y: 0 },

    control7: {
      x: 120,
      y: 0 },

    point7: {
      x: 130,
      y: 0 } };

  function mapDataRange(value) {
    // stackoverflow.com/a/929107/5707008
    // return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
    return (value - 0) * (svgViewBoxGraphMax - svgViewBoxGraphMin) / (svgViewBoxHeight - 0) + svgViewBoxGraphMin;
  }

  function updateSlider($element) {
    if ($element) {

      let rangeIndex = $element.getAttribute('data-slider-index'),
      range = ranges[rangeIndex],
      value = $element.value;

      if (range === value) {
        return; // No value change, no need to update then
      }
      // Update state
      ranges[rangeIndex] = value;

      let parent = $element.parentElement,
      $thumb = parent.querySelector('.range-slider__thumb'),
      $bar = parent.querySelector('.range-slider__bar'),
      pct = value * ((sliderHeight - sliderThumbSize) / sliderHeight);

      $thumb.style.bottom = `${pct}%`;
      $bar.style.height = `calc(${pct}% + ${sliderThumbSize / 2}px)`;
      //$thumb.textContent = `${value}%`;

      renderSliderGraph();
    }
  }

  function updatePoints() {
    // Convert from percentage to coordinate values    
    // Calculate and floor the values
    points.point1.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range1 / 100 | 0;
    points.point2.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range2 / 100 | 0;
    points.point3.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range3 / 100 | 0;
    points.point4.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range4 / 100 | 0;
    points.point5.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range5 / 100 | 0;
    points.point6.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range6 / 100 | 0;
    points.point7.y = svgViewBoxHeight - svgViewBoxHeight * ranges.range7 / 100 | 0;

    const max = svgViewBoxGraphMax;
    const min = svgViewBoxGraphMin;

    points.point1.y = mapDataRange(points.point1.y);
    points.point2.y = mapDataRange(points.point2.y);
    points.point3.y = mapDataRange(points.point3.y);
    points.point4.y = mapDataRange(points.point4.y);
    points.point5.y = mapDataRange(points.point5.y);
    points.point6.y = mapDataRange(points.point6.y);
    points.point7.y = mapDataRange(points.point7.y);

    // Update Y for the other points
    points.begin.y = points.point1.y;
    points.control1.y = points.point1.y;
    points.control2.y = points.point2.y;
    points.control3.y = points.point3.y;
    points.control4.y = points.point4.y;
    points.control5.y = points.point5.y;
    points.control6.y = points.point6.y;
    points.control7.y = points.point7.y;
  }

  function getInterpolatedLine(type) {

    let shadowOffset = 0;
    if (type === 'shadow') {
      shadowOffset = 10; // simple simulation, no fancy shadow algorithm
    }

    return 'M {0},{1} L {2},{3} C {4},{5} {6},{7} {8},{9} S {10} {11}, {12} {13} S {14} {15}, {16} {17} S {18} {19}, {20} {21} S {22} {23}, {24} {25} S {26} {27}, {28} {29}'.format(
    // M
    points.begin.x, points.begin.y,
    // L
    points.point1.x, points.point1.y,
    // C
    points.control1.x, points.control1.y,
    points.control2.x, points.control2.y + shadowOffset,
    points.point2.x, points.point2.y + shadowOffset,
    // S
    points.control3.x, points.control3.y,
    points.point3.x, points.point3.y,
    // S
    points.control4.x, points.control4.y + shadowOffset,
    points.point4.x, points.point4.y + shadowOffset,
    // S
    points.control5.x, points.control5.y,
    points.point5.x, points.point5.y,
    // S
    points.control6.x, points.control6.y + shadowOffset,
    points.point6.x, points.point6.y + shadowOffset,
    // S
    points.control7.x, points.control7.y,
    points.point7.x, points.point7.y);

  }

  function reset() {
    const inputs = app.inputs;
    inputs.forEach(input => input.value = 50);
    inputs.forEach(input => app.updateSlider(input));
  }

  function renderSliderGraph() {
    updatePoints();
    $svgLine.setAttribute('d', getInterpolatedLine());
    $svgLineShadow.setAttribute('d', getInterpolatedLine('shadow'));
  }

  function selectPreset(type) {
    // Generate random graph
    const inputs = app.inputs;
    inputs.forEach(input => input.value = Math.random() * 100 | 0);
    inputs.forEach(input => app.updateSlider(input));
  }

  return {
    inputs: [].slice.call(document.querySelectorAll('.sliders input')),
    updateSlider,
    reset,
    selectPreset };


})();

(function initAndSetupTheSliders() {
  const inputs = app.inputs;
  let index = 1;
  inputs.forEach(input => input.setAttribute('data-slider-index', 'range' + index++));
  inputs.forEach(input => input.value = 50);
  inputs.forEach(input => app.updateSlider(input));
  // Cross-browser support where value changes instantly as you drag the handle, therefore two event types.
  inputs.forEach(input => input.addEventListener('input', element => app.updateSlider(input)));
  inputs.forEach(input => input.addEventListener('change', element => app.updateSlider(input)));
  app.selectPreset('custom');
})();
//]]> 
</script>

Demikian Cara Membuat Slider Range Equalizer Responsive, di atas saya sudah tidak lagi menjelaskan secara detail pemasangan masing-masing script tersebut karena saya rasa jika sobat mencari tutorial tentang script untuk dipasang di blog pasti sudah tahu tempat masing masing script CSS, HTML dan JavaScript di atas. Jika Sobat ada pertanyaan, masukkan atau kritikan silahkan cantumkan di bawah kolom komentar yang sudah saya sediakan. Salam Blogger!!!

Hanya Blogger Pemula yang suka menulis dan membaca

Disqus Comments