I am trying to build a custom audio player. I am using HtmlAudioElement for that. I have managed to do play, pause, display duration and all but i have stuck where i need to show a progress bar when playing a track. I have percentage value( How much song already played ) which is updating every millisecond. I was wondering using that percentages value can i use canvas and draw vertical lines as percentage increases?
So this is how progress bar should change color as percentage increases. I have no idea where to start. I am very new to Canvas. Any Help ?
I have tried this so far. ( This is not what i want) .
const canvas = document.getElementById('progress');
canvas.width = 1920;
canvas.height = 100;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'grey';
for(let i = 0; i < 1000; i+=10){
console.log(i);
ctx.fillRect(i,0,5,100);
}
let count = 0;
let percent = 0;
ctx.fillStyle = 'orange';
function draw(){
console.log('Hello')
ctx.fillRect(count,0,5,100);
count+=10;
if(count > 100/1){
return;
}
window.requestAnimationFrame(draw);
}
draw();
So this what it looks right now.
I want as playing percentage changes i need to hook that value somewhere in Canvas so i can draw those lines.
Thanks in advance :)
You can read the value (% done) directly from the media object that holds it.
I can not workout what it is you are having trouble with. you mention color the following is a simple color changing bar.
Some constants to define the progress bar
const width = 500;
const height = 20;
const startColor = {r: 255, g: 128, b: 0}; // unsigned byte values 0 - 255
const endColor = {r: 255, g: 128, b: 0};
To interpolate the color
function progressColor(start, end, progress) {
const r = (end.r - start.r) * progress + start.r;
const g = (end.g - start.g) * progress + start.g;
const b = (end.b - start.b) * progress + start.b;
return `rgb(${r | 0},${g |0 }, ${b | 0})`;
}
To draw the bar
function progressBar(progress) {
ctx.fillStyle = progressColor(startColor, endColor, progress);
// whatever design you want the example is just a simple bar
ctx.fillRect(0,0, width * progress, height);
}
The main loop every 60th second.
If the audio is paused it stops.
Care must be taken when starting the animation loop not to start it more than once
Note that the audio will have stopped up to ~1/60th second before the last animation frame is rendered.
The main animation loop...
var progressAnimating = false; // this is to avoid more that one mainLoop playing
function mainLoop() {
ctx.clearRect(0,0,width,height);
// draw backing bar here
const fractionDone = audio.time / audio.duration;
progressBar(fractionDone);
// only while not paused
if (!audio.paused) {
requestAnimationFrame(mainLoop);
} else {
progressAnimating = false; // flag that the animation has stopped
}
}
Use the audio play event to start the animation.
Check to make sure that the animation is not playing before you request the first frame.
If the animation is still active then it will continue by its self
.
audio.addEventListener("play",() => {
if (!progressAnimating) {
requestAnimationFrame(mainLoop);
progressAnimating = true;
}
});
The next function replaces the solid bar from above. It uses the clip area to limit the width so you dont need to fiddle with fractional bars.
const barWidth = 4; // in px
const barSpacing = 8; // distance from left edge to next left edge in px
function progressBar(progress) {
ctx.save(); // save the unclipped state
ctx.beginPath(); // create the clip path
ctx.rect(0,0, width * progress, height);
ctx.clip();
ctx.fillStyle = progressColor(startColor, endColor, progress);
ctx.beginPath(); // draw all bars as one
var x = 0;
while (x < width * progress) {
ctx.rect(x, 0, barWidth, height);
x += barSpacing;
}
ctx.fill(); // draw that bars
ctx.restore(); // restore unclipped state
}