user12625952
user12625952

Reputation:

Slider seekbar drag function for the audio player on website

Yesterday, somebody very helpful converted the code for me into one that works fine but I'd like to format this code so that it has a draggable function. More specifically, I have a seekbar and to rewind a song I have to click on this seekbar and I can't drag it (you click and drag). I would like to add such a feature so that I can drag to scroll through the song. I have no idea what to do. :/ Here's code.

var audio = document.querySelectorAll('audio');
var playBtn = document.querySelectorAll('.play');
var seekBar = document.querySelectorAll('.seek-bar');
var fillBar = document.querySelectorAll('.fill');
var pointerdown = false;
var playing = undefined;

function getP(e, i) {
  var p = (e.clientX - seekBar[i].offsetLeft) / seekBar[i].clientWidth;
  p = clamp(0, p, 1);
  return p;
}

function clamp(min, val, max) {
  return Math.min(Math.max(min, val), max);
}

function updateFillBar(i, val) {
  fillBar[i].style.width = val + '%';
}

function handleTimeline(i) {
  if (pointerdown) return;
  var p = audio[i].currentTime / audio[i].duration;
  updateFillBar(i, p * 100);
}

function resetAudio(i) {
  audio[i].currentTime = 0;
  updateFillBar(i, 0);
}

function handleSeekbar(e, i) {
  pointerdown = true;
  var vidDur = audio[i].duration;
  var seekCoords = Math.round(
    (e.clientX - seekBar[i].offsetLeft) *
      (vidDur / seekBar[i].clientWidth)
  );
  handleAudioPlayback(i, seekCoords);
  var p = getP(e, i);
  updateFillBar(i, p * 100);
}

function handleButtonClick(i, time) {
  if (playing === undefined) {
    playing = i;
  }
  handleAudioPlayback(i, time);
}

function handleAudioPlayback(i, time) {
  if (playing !== i) {
    audio[playing].pause();
    playing = i;
  }
  var a = audio[i];
  if (pointerdown) {
    a.currentTime = time;
    a.play();
    pointerdown = false;
  } else if (a.paused) {
    a.play();
  } else {
    a.pause();
  }
}

audio.forEach((node, i) => {
  node.addEventListener('timeupdate', function(e) {
    handleTimeline(i);
  });
  node.addEventListener('ended', function(e) {
    resetAudio(i);
  });
  seekBar[i].addEventListener(
    'pointerdown',
    function(e) {
      handleSeekbar(e, i);
    },
    false
  );
  playBtn[i].addEventListener('click', function(e) {
    handleButtonClick(i, 0);
  });
});
<div class="audio-player">
  <audio src="https://milessite.com/music/music.mp3"></audio>
  <button class="play">play</button>
  <div class="seek-bar">
    <div class="fill"><div class="handle"></div></div>
  </div>
</div>
<div class="audio-player">
  <audio src="https://milessite.com/music/music1.mp3"></audio>
  <button class="play">play</button>
  <div class="seek-bar">
    <div class="fill"><div class="handle"></div></div>
  </div>
</div>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background: #0f0f0f;
  color: #fff;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  touch-action: none;
}
.audio-player {
  width: 80%;
  height: 200px;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
  border-radius: 10px;
}
.play {
  width: 40px;
  height: 40px;
  background-color: #fff;
  border-radius: 50%;
  margin-bottom: 30px;
  outline: none;
  border: none;
}
.play:focus {
  background-color: #ff0;
}
.seek-bar {
  width: 90%;
  margin: 0 auto;
  height: 4px;
  border-radius: 4px;
  background-color: rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  cursor: pointer;
}
.fill {
  height: 4px;
  border-radius: 4px;
  background-color: #fff;
  position: relative;
}
.handle {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  position: absolute;
  right: 0;
  top: 50%;
  background: #fff;
  transform: translate(50%, -50%) scale(0);
  transition: transform 0.2s;
}
.seek-bar:hover .handle {
  transform: translate(50%, -50%) scale(1);
}

Upvotes: 0

Views: 1682

Answers (1)

Jason Y
Jason Y

Reputation: 1011

It's going to make much more sense to use an HTML range slider. The below simplifies your code quite a bit as well.

var audio = document.querySelectorAll('audio');
var playBtn = document.querySelectorAll('.play');
var seekBar = document.querySelectorAll('.seek-bar');
var fillBar = document.querySelectorAll('.fill');
var seek = document.querySelectorAll('.seek');
var seeking = false;
var playing = undefined;

function updateProgress(i) {
  var duration = audio[i].duration;
  var multiplier = 100 / duration;
  var currentTime = audio[i].currentTime;
  seek[i].value = currentTime * multiplier;
}

function resetAudio(i) {
  audio[i].currentTime = 0;
  updateProgress(i, 0);
}

function handleSeek(e, i) {
  seeking = true;
  var seekPosition = e.target.value / 100;
  var playFrom = audio[i].duration * seekPosition;
  handleAudioPlayback(i, playFrom);
  updateProgress(i);
}

function handleButtonClick(i, time) {
  if (playing === undefined) {
    playing = i;
  }
  handleAudioPlayback(i, time);
}

function handleAudioPlayback(i, time) {
  var seekPosition = seek[i].value;
  if (playing !== i && !seeking) {
    audio[playing].pause();
    playing = i;
  }
  var a = audio[i];
  if (seeking) {
    a.currentTime = time;
    seeking = false;
  } else if (a.paused) {
    a.play();
  } else {
    a.pause();
  }
}

audio.forEach((node, i) => {
  node.addEventListener('timeupdate', function(e) {
    updateProgress(i);
  });
  node.addEventListener('ended', function(e) {
    resetAudio(i);
  });
  playBtn[i].addEventListener('click', function(e) {
    handleButtonClick(i, 0);
  });
  seek[i].addEventListener('change', function(e) {
    handleSeek(e, i);
  });
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background: #0f0f0f;
  color: #fff;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  touch-action: none;
}
.audio-player {
  width: 80%;
  height: 200px;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
  border-radius: 10px;
}
.play {
  width: 40px;
  height: 40px;
  background-color: #fff;
  border-radius: 50%;
  margin-bottom: 30px;
  outline: none;
  border: none;
}
.play:focus {
  background-color: #f90;
}
input[type='range'] {
  -webkit-appearance: none;
  overflow: hidden;
  display: flex;
  height: 4px;
  margin: 0 auto;
  width: 90%;
}
input[type='range']:focus {
  outline: none;
}
input[type='range']::-webkit-slider-runnable-track {
  width: 100%;
  height: 4px;
  background: #434343;
}
input[type='range']::-webkit-slider-thumb {
  border: 1px solid #000000;
  height: 20px;
  width: 16px;
  background: #666;
  box-shadow: -2000px 0 0 2000px #fff;
  cursor: pointer;
  -webkit-appearance: none;
  margin-top: -4px;
}
input[type='range']::-moz-range-track {
  width: 100%;
  height: 4px;
  background: #434343;
}
input[type='range']::-moz-range-progress {
  height: 4px;
  background-color: #fff;
}
input[type='range']::-moz-range-thumb {
  border: 1px solid #000000;
  height: 20px;
  width: 16px;
  border-radius: 3px;
  background: #666;
  cursor: pointer;
}
input[type='range']::-ms-track {
  width: 100%;
  height: 4px;
  cursor: pointer;
  background: transparent;
  border-color: transparent;
  border-width: 16px 0;
  color: transparent;
}
input[type='range']::-ms-fill-lower {
  background: #3f3f3f;
  border: 0.2px solid #010101;
  border-radius: 2.6px;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type='range']::-ms-fill-upper {
  background: #3f3f3f;
  border: 0.2px solid #010101;
  border-radius: 2.6px;
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type='range']::-ms-thumb {
  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
  border: 1px solid #000000;
  height: 4px;
  width: 16px;
  border-radius: 3px;
  background: #ffffff;
  cursor: pointer;
}
input[type='range']:focus::-ms-fill-lower {
  background: #3f3f3f;
}
input[type='range']:focus::-ms-fill-upper {
  background: #3f3f3f;
}
<div class="audio-player">
  <audio src="https://milessite.com/music/music.mp3"></audio>
  <button class="play">play</button>
  <input
    class="seek"
    type="range"
    min="0"
    max="100"
    value="0"
    step="0.0001"
  />
</div>
<div class="audio-player">
  <audio src="https://milessite.com/music/music1.mp3"></audio>
  <button class="play">play</button>
  <input
    class="seek"
    type="range"
    min="0"
    max="100"
    value="0"
    step="0.0001"
  />
</div>

Upvotes: 1

Related Questions