Chunked Slider animation

by slawe

HTML

<!DOCTYPE html>
<div id="sliderContainer">
  <div class="chunk" style="background: #d5c78f"></div> <!-- 2 -->
  <div class="chunk" style="background: #f39c12"></div> <!-- 3 -->
  <div class="chunk" style="background: #e74c3c"></div> <!-- 4 -->
  <div class="chunk" style="background: #2ecc71"></div> <!-- 5 (center) -->
  <div class="chunk" style="background: #e74c3c"></div> <!-- 4 -->
  <div class="chunk" style="background: #f39c12"></div> <!-- 3 -->
  <div class="chunk" style="background: #d5c78f"></div> <!-- 2 -->
  <div id="thumb"></div>
</div>
<div id="valueDisplay">Value: </div>

CSS

body {
  font-family: sans-serif;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 50px;
}

#sliderContainer {
  width: 500px;
  height: 40px;
  position: relative;
  display: flex;
  cursor: pointer;
  border-radius: 10px;
  overflow: hidden;
}

.chunk {
  flex: 1;
  height: 100%;
}

#thumb {
  width: 10px;
  height: 50px;
  background: black;
  position: absolute;
  top: -5px;
  border-radius: 5px;
}

#valueDisplay {
  margin-top: 20px;
  font-size: 24px;
}

JavaScript

const thumb = document.getElementById('thumb');
  const slider = document.getElementById('sliderContainer');
  const display = document.getElementById('valueDisplay');

  const sliderWidth = slider.offsetWidth;
  const centerX = sliderWidth / 2;
  let position = 0;
  let direction = 1;
  let running = true;

  // Function to map position to value (based on chunk)
  function getValue(pos) {
    const chunkSize = sliderWidth / 7;
    const index = Math.floor(pos / chunkSize);
    return [2, 3, 4, 5, 4, 3, 2][Math.min(index, 6)];
  }

  // Speed increases near center (value 5)
  function getSpeed(pos) {
    const distFromCenter = Math.abs(pos - centerX);
    const maxDist = centerX;
    const baseSpeed = 3;
    const speedFactor = 35; // higher = faster at center
    return baseSpeed + (1 - distFromCenter / maxDist) * speedFactor;
  }

  function animate() {
    if (!running) return;
    const speed = getSpeed(position);
    position += direction * speed;

    if (position >= sliderWidth) {
      direction = -1;
      position = sliderWidth;
    } else if (position <= 0) {
      direction = 1;
      position = 0;
    }

    thumb.style.left = `${position}px`;
    display.textContent = `Value: ${getValue(position)}`;

    requestAnimationFrame(animate);
  }

  animate();

  slider.addEventListener('click', () => {
    running = false;
  });