I have an audio script with play/pause, I want to make the audio stop when I click on the square button at the left, and to add the timing to the right
here is the code: https://codepen.io/Amirafik/pen/YzxQZQw
HTML
<div class="title">
Dina Mohamed
</div>
<div class="stop"></div>
<div id="audioButton">
<div id="playerContainer">
<div class="listen">LISTEN</div>
</div>
</div>
<div class="duration">
00:12
</div>
<br>_____________________________________________________</br>
<div class="note">
<p>All items were more than perfect, we loved the experience and will order ONE OAK services again in the future for sure. <!--<span style="color:#F04E36"><br> Dina sent us an amazing feedback about her experience, tap the play button to listen to her cheerful words.</span></p>-->
</div
CSS
@import url('https://fonts.googleapis.com/css?family=montserrat:100,200,300,400,500,600,700,800,900');
body {
background: #ffffff;
color: #000000;
font-size: 16px ;
font-family: "montserrat" ;
font-weight: 500;
-webkit-tap-highlight-color: transparent;
}
a {
color: #F04E36;
}
.title {
max-width: 700px;
margin: 0 auto;
color: #000000;
font-weight:700;
display:inline-block;
}
.note {
max-width: 380px;
margin: 0 auto;
color: #000000;
display:inline-block;
}
.circle-audio-player {
cursor: pointer;
width:25px;
padding:0px;
margin-top:-67%;
margin-bottom:-50%;
margin-left:-7px;
background-color:#EDEBE7;
border-radius:50%;
vertical-align:middle;
}
#playerContainer {
padding: 0px;
vertical-align:middle;
}
#audioButton {
border-radius: 50px;
border: 2px solid #000000;
padding: 10px;
max-width: 85px;
height: 10px;
display: inline-block;
vertical-align:middle;
margin-left:2px;
}
.listen {
margin-left: 5px;
color: #000000;
font-weight:700;
display:inline-block;
float:right;
vertical-align:middle;
margin-top:-5%;
font-size: 14px ;
}
.stop {
max-width: 500px;
margin-left:10px;
height: 10px;
width: 10px;
background-color: #000000;
font-weight:500;
font-size: 14px ;
display:inline-block;
vertical-align:middle;
}
.duration {
max-width: 500px;
margin-left: 2px;
color: #000000;
font-weight:500;
font-size: 14px ;
display:inline-block;
}
JS
// settings
var DEFAULTS = {
borderColor: "#EDEBE7",
playedColor: "#F04E36",
backgroundColor: "#d3cdc2",
iconColor: "#000000",
borderWidth: 2,
size: 48,
className: 'circle-audio-player'
};
// reused values
var pi = Math.PI;
var doublePi = pi * 2;
var arcOffset = -pi / 2;
var animTime = 200;
var loaderTime = 1800;
var CircleAudioPlayer = function (options) {
options = options || {};
for (var property in DEFAULTS) {
this[property] = options[property] || DEFAULTS[property];
}
// create some things we need
this._canvas = document.createElement('canvas');
this._canvas.setAttribute('class', this.className ' is-loading');
this._canvas.addEventListener('mousedown', (function () {
if (this.playing) {
this.pause();
}
else {
this.play();
}
}).bind(this));
this._ctx = this._canvas.getContext('2d');
// set up initial stuff
this.setAudio(options.audio);
this.setSize(this.size);
// redraw loop
(function cAPAnimationLoop (now) {
// check if we need to update anything
if (this.animating) {
this._updateAnimations(now);
}
if (this._forceDraw || this.playing || this.animating || this.loading) {
this._draw();
this._forceDraw = false;
}
requestAnimationFrame(cAPAnimationLoop.bind(this));
}).call(this, new Date().getTime());
};
CircleAudioPlayer.prototype = {
// private methods
_animateIcon: function (to, from) {
// define a few things the first time
this._animationProps = {
animStart: null,
from: from,
to: to
};
if (from) {
this.animating = true;
}
else {
this._animationProps.current = this._icons[to].slice();
this.draw();
}
},
_updateAnimations: function (now) {
this._animationProps.animStart = this._animationProps.animStart || now;
var deltaTime = now - this._animationProps.animStart;
var perc = (1 - Math.cos(deltaTime / animTime * pi / 2));
if (deltaTime >= animTime) {
this.animating = false;
perc = 1;
this._animationProps.current = this._icons[this._animationProps.to].slice();
this.draw();
}
else {
var from = this._icons[this._animationProps.from];
var current = [];
for (var i = 0; i < from.length; i ) {
current.push([]);
for (var j = 0; j < from[i].length; j ) {
current[i].push([]);
var to = this._icons[this._animationProps.to][i][j];
current[i][j][0] = from[i][j][0] (to[0] - from[i][j][0]) * perc;
current[i][j][1] = from[i][j][1] (to[1] - from[i][j][1]) * perc;
}
}
this._animationProps.current = current;
}
},
_draw: function (progress) {
// common settings
if (isNaN(progress)) {
progress = this.audio.currentTime / this.audio.duration || 0;
}
// clear existing
this._ctx.clearRect(0, 0, this.size, this.size);
// draw bg
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), 0, doublePi);
this._ctx.closePath();
this._ctx.fillStyle = this.backgroundColor;
this._ctx.fill();
// draw border
// our active path is already the full circle, so just stroke it
this._ctx.lineWidth = this.borderWidth;
this._ctx.strokeStyle = this.borderColor;
this._ctx.stroke();
// play progress
if (progress > 0) {
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize - (this.borderWidth / 2), arcOffset, arcOffset doublePi * progress);
this._ctx.strokeStyle = this.playedColor;
this._ctx.stroke();
}
// icons
this._ctx.fillStyle = this.iconColor;
if (this.loading) {
var loaderOffset = -Math.cos((new Date().getTime() % (loaderTime)) / (loaderTime) * pi) * doublePi - (pi / 3) - (pi / 2);
this._ctx.beginPath();
this._ctx.arc(this._halfSize, this._halfSize, this._halfSize / 3, loaderOffset, loaderOffset pi / 3 * 2);
this._ctx.strokeStyle = this.iconColor;
this._ctx.stroke();
}
else {
this._ctx.beginPath();
var icon = (this._animationProps && this._animationProps.current) || this._icons.play;
for (var i = 0; i < icon.length; i ) {
this._ctx.moveTo(icon[i][0][0], icon[i][0][1]);
for (var j = 1; j < icon[i].length; j ) {
this._ctx.lineTo(icon[i][j][0], icon[i][j][1]);
}
}
// this._ctx.closePath();
this._ctx.fill();
// stroke to fill in for retina
this._ctx.strokeStyle = this.iconColor;
this._ctx.lineWidth = 2;
this._ctx.lineJoin = 'miter';
this._ctx.stroke();
}
},
_setState: function (state) {
this.playing = false;
this.loading = false;
if (state === 'playing') {
this.playing = true;
this._animateIcon('pause', 'play');
}
else if (state === 'loading') {
this.loading = true;
}
else if (this.state !== 'loading') {
this._animateIcon('play', 'pause');
}
else {
this._animateIcon('play', null);
}
this.state = state;
this._canvas.setAttribute('class', this.className ' is-' state);
this.draw();
},
// public methods
draw: function () {
this._forceDraw = true;
},
setSize: function (size) {
this.size = size;
this._halfSize = size / 2; // we do this a lot. it's not heavy, but why repeat?
this._canvas.width = size;
this._canvas.height = size;
// set icon paths
var iconSize = this.size / 2;
var pauseGap = iconSize / 10;
var playLeft = Math.cos(pi / 3 * 2) * (iconSize / 2) this._halfSize;
var playRight = iconSize / 2 this._halfSize;
var playHalf = (playRight - playLeft) / 2 playLeft;
var top = this._halfSize - Math.sin(pi / 3 * 2) * (iconSize / 2);
var bottom = this.size - top;
var pauseLeft = this._halfSize - iconSize / 3;
var pauseRight = this.size - pauseLeft;
this._icons = {
play: [
[
[playLeft, top],
[playHalf, (this._halfSize - top) / 2 top],
[playHalf, (this._halfSize - top) / 2 this._halfSize],
[playLeft, bottom]
],
[
[playHalf, (this._halfSize - top) / 2 top],
[playRight, this._halfSize],
[playRight, this._halfSize],
[playHalf, (this._halfSize - top) / 2 this._halfSize]
]
],
pause: [
[
[pauseLeft, top pauseGap],
[this._halfSize - pauseGap, top pauseGap],
[this._halfSize - pauseGap, bottom - pauseGap],
[pauseLeft, bottom - pauseGap]
],
[
[this._halfSize pauseGap, top pauseGap],
[pauseRight, top pauseGap],
[pauseRight, bottom - pauseGap],
[this._halfSize pauseGap, bottom - pauseGap]
]
]
};
if (this._animationProps && this._animationProps.current) {
this._animateIcon(this._animationProps.to);
}
if (!this.playing) {
this.draw();
}
},
setAudio: function (audioUrl) {
this.audio = new Audio(audioUrl);
this._setState('loading');
this.audio.addEventListener('canplaythrough', (function () {
this._setState('paused');
}).bind(this));
this.audio.addEventListener('play', (function () {
this._setState('playing');
}).bind(this));
this.audio.addEventListener('pause', (function () {
// reset when finished
if (this.audio.currentTime === this.audio.duration) {
this.audio.currentTime = 0;
}
this._setState('paused');
}).bind(this));
},
appendTo: function (element) {
element.appendChild(this._canvas);
},
play: function () {
this.audio.play();
},
pause: function () {
this.audio.pause();
}
};
// now init one as an example
var cap = new CircleAudioPlayer({
audio: 'https://www.siriusxm.com/content/dam/sxm-com/audio/test/audio-previews/audio_test03.mp3.png',
size: 120,
borderWidth: 8
});
cap.appendTo(playerContainer);
CodePudding user response:
You can simply use AudioElement.pause()
to pause an running element, and the next AudioElement.play()
will start from where you left off.
You can essentially set the currentTime
property of the audio element to start from the beginning
A simple demonstration of how it works
const pause = document.getElementById('pause');
const stop = document.getElementById('stop');
const play = document.getElementById('play');
const container = document.getElementById('player');
const duration = document.getElementById('duration');
const audio = new Audio('https://www.siriusxm.com/content/dam/sxm-com/audio/test/audio-previews/audio_test03.mp3.png');
let played = 0;
let playing = true;
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
run = async function () {
while(playing) {
if (played == Math.floor(audio.duration)) break;
duration.innerText = `${played} / ${Math.floor(audio.duration)}`;
played ;
await wait(1000);
}
}
container.appendChild(audio);
stop.addEventListener('click', () => {
duration.innerText = `0 / ${Math.floor(audio.duration)}`
audio.pause();
audio.currentTime = 0;
played = 0;
playing = false;
});
pause.addEventListener('click', () => {
audio.pause();
playing = false;
});
play.addEventListener('click', () => {
playing = true
audio.play();
run();
});
<div id="player"></div>
<div id="duration">0.0</div>
<button id="play">play</button>
<button id="stop">stop</button>
<button id="pause">pause</button>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>