Zach Boyd McTague
Zach Boyd McTague

Reputation: 311

Custom progress bar for <audio> and <progress> HTML5 elements

I am mind boggled at working out how to create a custom seekbar for an audio player using the tag and simple Javascript.

Current Code:

    <script>
  function play() {
   document.getElementById('player').play();
  }

  function pause() {
   document.getElementById('player').pause();
  }
</script>


<audio src="sample.mp3" id="player"></audio>  
<button onClick="javascript:play()" >Play</button>
<button onClick="javascript:pause()" >Pause</button>
<progress id="seekbar"></progress>

Would it be possible to link the progress bar so that when i play a song the progress is shown?

Upvotes: 30

Views: 67619

Answers (4)

ggorlen
ggorlen

Reputation: 57344

Here's a simple vanilla example:

const url = "https://upload.wikimedia.org/wikipedia/en/a/a9/Webern_-_Sehr_langsam.ogg";
const audio = new Audio(url);
const playBtn = document.querySelector("button");
const progressEl = document.querySelector('input[type="range"]');
let mouseDownOnSlider = false;

audio.addEventListener("loadeddata", () => {
  progressEl.value = 0;
});
audio.addEventListener("timeupdate", () => {
  if (!mouseDownOnSlider) {
    progressEl.value = audio.currentTime / audio.duration * 100;
  }
});
audio.addEventListener("ended", () => {
  playBtn.textContent = "▶️";
});

playBtn.addEventListener("click", () => {
  audio.paused ? audio.play() : audio.pause();
  playBtn.textContent = audio.paused ? "▶️" : "⏸️";
});

progressEl.addEventListener("change", () => {
  const pct = progressEl.value / 100;
  audio.currentTime = (audio.duration || 0) * pct;
});
progressEl.addEventListener("mousedown", () => {
  mouseDownOnSlider = true;
});
progressEl.addEventListener("mouseup", () => {
  mouseDownOnSlider = false;
});
button {
  font-size: 1.5em;
}
<button>▶️</button>
<input type="range" value="0" min="0" max="100" step="1">

The approach is to use an input[type="range"] slider to reflect the progress and allow the user to seek through the track. When the range changes, set the audio.currentTime attribute, using the slider as a percent (you could also adjust the max attribute of the slider to match the audio.duration).

In the other direction, I update the slider's progress on timeupdate event firing.

One corner case is that if the user scrolls around with their mouse down on the slider, the timeupdate event will keep firing, causing the progress to hop around between wherever the user's cursor is hovering and the current audio progress. I use a boolean and the mousedown/mouseup events on the slider to prevent this from happening.


See also JavaScript - HTML5 Audio / custom player's seekbar and current time for an extension of this code that displays the time.

Upvotes: 7

jbalsas
jbalsas

Reputation: 3512

Yes, it is possible using the timeupdate event of the audio tag. You receive this event every time the position of the playback is updated. Then, you can update your progress bar using the currentTime and duration properties of the audio element.

You can see a working example in this fiddle

Upvotes: 39

Vladislav Filonov
Vladislav Filonov

Reputation: 163

If you want smooth progress bar,try somethink like that

HTML:

<div class="hp_slide">
     <div class="hp_range"></div>
</div>

CSS:

.hp_slide{
    width:100%;
    background:white;
    height:25px;
}
.hp_range{
    width:0;
    background:black;
    height:25px;
}

JS:

var player = document.getElementById('player');    
player.addEventListener("timeupdate", function() {
    var currentTime = player.currentTime;
    var duration = player.duration;
    $('.hp_range').stop(true,true).animate({'width':(currentTime +.25)/duration*100+'%'},250,'linear');
});

Pretty rough,but works

Upvotes: 14

Calvein
Calvein

Reputation: 2121

First of all, don't use the progress element, it's a shitty element (for now) and styling it is a huge pain in... well it's boring (look at a little project I made, look at it (and it's juste webkit/moz)).

Anyway, you should read the doc on MDN, it's very easy and with a lot of examples. What you are looking for is the currentTime attribute, here a little snippet :

var audio = document.querySelector('#player')
audio.currentTime = 60 // will go to the 60th second

So what you need is to use the cross-multiplication (div is the element you use as a progress bar) : Where I clicked on div | THE TIME I WANT TO KNOW
————————————————————————————————————————
Total length of div | The total time of my video/audio (audio.seekable.end())

Upvotes: 1

Related Questions