)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Range Slider and Progress Bar

  1. const NUM = 8;
  2. const NUM_M_1 = NUM - 1;
  3. const ui = document.createElement('div')
  4. ui.innerHTML = `
  5.   <div class="ui">
  6.     <div class="progress" data-ref>
  7.       <div class="progressFill" data-ref></div>
  8.     </div>
  9.     <div class="text" data-ref>
  10.     0% of 100%
  11.     </div>
  12.  
  13.     <div class="dots" data-ref>
  14.     ${
  15.       `<div></div>`.repeat(NUM)
  16.     }
  17.     </div>
  18.  
  19.     <label>
  20.       drag the slider...
  21.       <input class="slider" type="range" min="0" max="100" step="1" value="0" data-ref/>
  22.     </label>
  23.   </div>
  24.   <style>
  25.     body {
  26.       font-family: sans-serif;
  27.     }
  28.     .progress, .dots {
  29.       position: relative;
  30.       width: 80%;
  31.       margin: 0 auto;
  32.       height: 30px;
  33.       border: 1px solid black;
  34.     }
  35.     .progressFill {
  36.       height: 100%;
  37.       width: 0;
  38.       background: red;
  39.     }
  40.     .text {
  41.       padding: 1em;
  42.       background: #ccc;
  43.       margin: .5em;
  44.       font-weight: bold;
  45.     }
  46.     label {
  47.       display: block;
  48.       margin: 1em;
  49.     }
  50.     .slider {
  51.       cursor: pointer;
  52.     }
  53.     .dots {
  54.       border: none;
  55.     }
  56.     .dots div {
  57.       height: 100%;
  58.       width: ${100 / NUM}%;
  59.       float: left;
  60.       transition: background 400ms ease-out;
  61.       background: transparent;
  62.       border-radius: 500px;
  63.       box-shadow: inset 0 0px 0 3px blue;
  64.     }
  65.     .dots div:nth-child(1) {
  66.       background: red;
  67.     }
  68.  
  69.   </style>
  70. `;
  71. document.body.appendChild(ui);
  72.  
  73. // select everything with a `data-ref`
  74. const els = {};
  75. ;[...document.querySelectorAll('[data-ref]')]
  76.   .forEach(el => {
  77.     els[el.classList[0]] = el;
  78.   });
  79.  
  80. function update(e) {
  81.  
  82.   // normal prog bar
  83.   const val = e.target.value;
  84.   els.progressFill.style.width = `${val}%`;
  85.   els.text.innerHTML = `
  86.     ${val}% of 100%
  87.   `;
  88.  
  89.   // segmented dot prog bar
  90.   const idx = Math.floor(val / (100 / NUM));
  91.   if (idx < NUM) { 
  92.     for (let i = 0; i < NUM; i++) {
  93.       els.dots.children[i]
  94.         .style.background = i <= idx ? 'red' : 'white'
  95.     }
  96.   }
  97. }
  98.  
  99. els.slider.addEventListener('input', update);
  100. els.slider.addEventListener('change', update);

Drag slider and watch two progress bars and a text readout update. There are some interesting vanilla tricks in this one.

This trick and a variety of variations on it is pretty powerful:

  1. const els = {};
  2. [...document.querySelectorAll('[data-ref]')].forEach(el => {
  3.   els[el.classList[0]] = el;
  4. });
// css // dom // graphics // javascript // math // strings // tricks // ui
snippet.zone ~ 2021-24 /// {s/z}