Vanilla JS image slideshow play/pause button - javascript

My play/pause button works the first time I press pause and the first time I press play. But after that if I want to pause the slideshow again, it just plays the slideshow at a faster speed and I am no longer able to pause it.
I am thinking maybe it is to do with the fact I have two separate functions: one for the play/pause button icon toggle, and another for the actual play pause behaviour? (update: this has now been fixed, but still doesn't work)
Sorry, I am struggling with javascript, I have a lot to learn.
My script:
const playPause = document.querySelector('.pause');
let slideId;
// FUNCTION TO MOVE TO NEXT SLIDE
const moveToNextSlide = () => {
slides = getSlides();
if (index >= slides.length - 1) return;
index++;
slideGroup.style.transform = `translateX(${-slideWidth * index}px)`;
slideGroup.style.transition = '.8s';
}
// FUNCTION TO START SLIDESHOW
const startSlide = () => {
slideId = setInterval(() => {
moveToNextSlide();
}, interval);
playing = true;
};
// START AUTOMATIC SLIDESHOW UPON ENTERING THE PAGE
startSlide();
//PLAY PAUSE BUTTON - slideshow start/stop
playPause.addEventListener('click', () => {
if(!slideId) {
slideId = startSlide();
console.log('started');
} else {
clearInterval(slideId);
slideId = null;
console.log('stopped');
}
});
//PLAY PAUSE BUTTON - image change
function toggle(button) {
if (button.className != 'pause') {
button.src = 'img/pause.png';
button.className = 'pause';
}
else if (button.className == 'pause') {
button.src = 'img/play.png';
button.className = 'play';
}
return false;
}
HTML:
<input type='image' src='img/pause.png' class='pause' onclick='toggle(this);' />
This is what the console looks like when I try to pause the slideshow for a second time:

There are some details in your code that are missing and would be helpful to have, but I guess that you can get rid of the onclick handler and attach two event listeners:
let slideId;
// FUNCTION TO START SLIDESHOW
const startSlide = () => {
let interval = 2000; // using just as sample
playing = true;
return setInterval(() => {
console.log('moveToNextSlide();') // replaced just to test without missing code
}, interval);
};
//PLAY PAUSE BUTTON - slideshow start/stop
playPause.addEventListener('click', () => {
if(!slideId) {
slideId = startSlide();
console.log('started');
} else {
clearInterval(slideId);
slideId = null;
console.log('stopped');
}
});
//PLAY PAUSE BUTTON - image change
playPause.addEventListener('click', function toggle() { // the arrow function would not work in this case
var button = this;
if (button.className != 'pause') {
button.src = 'img/pause.png';
button.className = 'pause';
}
else if (button.className == 'pause') {
button.src = 'img/play.png';
button.className = 'play';
}
return false;
});

Related

Unable to pause audio after eventListener end

When first loading the code, the pause button works fine, it pauses the audio and changes the HTML class of the button inside, the button continues to work after using the previous/next buttons to go to another song, however after the eventListener is triggered the pause button stops working, it doesn't pause the songs but the HTML inside still changes.
Edit: After a little bit of further debugging I found that the pause button is only able to pause the first time a track is loaded, once the audio.addEventListener('ended', nextTrack); is triggered it is unable to pause/play any audio.
let audio = new Audio;
let playing = false;
let playpause = document.getElementById('play-pause');
let root = document.documentElement;
let songname = document.getElementById('name');
let next = document.getElementById('next');
let prev = document.getElementById('previous');
let index = 0;
songlist = [
{"name":"Love Again"
,"artist":"The Kid LAROI",
"path":"resources/music/love-again.mp3",
},
{
"name":"Always Do",
"artist":"The Kid LAROI",
"path":"resources/music/always-do.mp3",
},
{
"name":"Bye Bye",
"artist":"Juice WRLD",
"path":"resources/music/bye-bye.mp3",
},
{
"name":"Understand",
"artist":"BoyWithUke",
"path":"resources/music/understand.mp3",
}
]
function progress_animation(){
var currentTime = audio.currentTime;
var duration = audio.duration;
$('#progbar').stop(true, true).animate({ 'width': (currentTime + .25) / duration * 100 + '%' }, 250, 'linear');
window.requestAnimationFrame(progress_animation);
};
function load(index){
songname.textContent = `${songlist[index].artist} - ${songlist[index].name}`;
audio.src = songlist[index].path;
audio.load()
};
audio.addEventListener('ended', nextTrack);
$('#play-pause').click(function (){
if (!playing) {
Play()
playing = true
} else {
Pause()
playing = false
}
});
function nextTrack(){
if (index < songlist.length - 1) {
index++;
} else {
index = 0;
}
load(index);
};
function prevTrack(){
if (index > 0) {
index--;
} else {
index = songlist.length - 1;
}
load(index);
};
function Play() {
audio.play();
playing = true;
playpause.innerHTML = '<i class="fa-solid fa-pause"></i>';
};
function Pause() {
audio.pause()
playing = false;
playpause.innerHTML = '<i class="fa-solid fa-play"></i>';
};
The pause button still changes its HTML class and sets the "playing" variable to false/true depending on the state of "playing" but doesn't actually pause the song

setInterval, click something then clearInterval, and then few seconds setInterval again

i want to create a slider image that running uses setInterval, when i click on the thumbail, the image slider stops, but after a few seconds i want it continues to run setInterval again, i'm stuck here. I don't know how to write the code so that setInterval runs again
//auto animate
let counter = 0;
function imageChange() {
bigImage.src = thumb[counter++].src;
if(counter >= thumb.length) {
counter = 0;
}
}
let gallery = setInterval(imageChange, 1000);
//click thumb stop Animate then runs again
for(t of thumb) {
t.addEventListener('click', (e) => {
bigImage.src = e.target.src;
clearInterval(gallery);
//I'm stuck here :(
});
}
pause = setTimeout(() => { gallery = setInterval(imageChange, 1000)} ,3000);
like this
let pause;
//auto animate
let counter = 0;
function imageChange() {
bigImage.src = thumb[counter++].src;
if(counter >= thumb.length) {
counter = 0;
}
}
let gallery = setInterval(imageChange, 1000);
//click thumb stop Animate then runs again
for(t of thumb) {
t.addEventListener('click', (e) => {
bigImage.src = e.target.src;
clearInterval(gallery);
clearTimeout(pause);
pause = setTimeout(() => { gallery = setInterval(imageChange, 1000)} ,3000);
});
}
I would delegate though
let pause;
//auto animate
let counter = 0;
function imageChange() {
bigImage.src = thumb[counter++].src;
if(counter >= thumb.length) {
counter = 0;
}
}
let gallery = setInterval(imageChange, 1000);
//click thumb stop Animate then runs again
document.getElementById('thumbContainerId').addEventListener('click',function(e) {
bigImage.src = e.target.src;
clearInterval(gallery);
clearTimeout(pause);
pause = setTimeout(() => { gallery = setInterval(imageChange, 1000)} ,3000);
});
You cannot PAUSE the setInterval function, you can either STOP it (clearInterval), or let it run.
When you click on, just set isPaused as true. When close a thumbnail set isPaused as false.
//auto animate
let counter = 0;
let isPaused = false;
function imageChange() {
if(isPaused){
return;
}
//Your code
}
let gallery = setInterval(imageChange, 1000);
//click thumb stop Animate then runs again
for(t of thumb) {
t.addEventListener('click', (e) => {
bigImage.src = e.target.src;
isPaused = true;
});
}
function closeThumnail(){
isPaused = false;
}

Stop loop on progressbar

I'm working with this progressbar:
https://codepen.io/thegamehasnoname/pen/JewZrm
The problem I have is it loops and what I want to achieve is:
stop on last progress slide (stop loop).
if the user is on last progressbar slide after it has stopped and I click on a .button-prev button it should start from the previous slide, not the first slide of the progressbar.
here is the code:
// swiper custom progressbar
const progressContainer = document.querySelector('.progress-container');
const progress = Array.from(document.querySelectorAll('.progress'));
const status = document.querySelector('.status');
const playNext = (e) => {
const current = e && e.target;
let next;
if (current) {
const currentIndex = progress.indexOf(current);
if (currentIndex < progress.length) {
next = progress[currentIndex+1];
}
current.classList.remove('active');
current.classList.add('passed');
}
if (!next) {
progress.map((el) => {
el.classList.remove('active');
el.classList.remove('passed');
})
next = progress[0];
}
next.classList.add('active');
}
progress.map(el => el.addEventListener("animationend", playNext, false));
playNext();
I tried adding this:
if (current) {
if (!next) {
$('.progress-container div').addClass('passed');
}
}
But the class passed gets deleted and the progressbar starts again.
This is the js of the previous button I have:
$(document).on('click', ".button-prev", function() {
$('.progress-container div.active').prev().removeClass('passed').addClass('active');
$('.progress-container div.active').next().removeClass('active');
});
any ideas on how to achieve this?
You almost have the fix ! Simply add a return statement to avoid to set the active calss to the first progress element.
if (current) {
const currentIndex = progress.indexOf(current);
if (currentIndex < progress.length) {
next = progress[currentIndex+1];
}
current.classList.remove('active');
current.classList.add('passed');
if (!next) {
$('.progress-container div').addClass('passed');
return;
}
}

how to get slide indicator to match current slide?

I have made this vanilla js image slider with three images. In the html i have three indicator dots at the bottom of the slider and a css active class for the active indicator. Can't figure out how to get the class to add to the current slide of the slide show, any help?
let sliderImages = document.querySelectorAll('.slides'),
prevArrow = document.querySelector('#prevBtn'),
nextArrow = document.querySelector('#nextBtn'),
dots = document.querySelectorAll('.indicator__dot'),
current = 0;
reset = () => {
for(let i = 0; i <sliderImages.length; i++) {
sliderImages[i].style.display = 'none';
}
}
startSlide = () => {
reset();
sliderImages[0].style.display = 'block'
}
prevSlide = () => {
reset();
sliderImages[current - 1].style.display = 'block';
current -- ;
}
nextSlide = () => {
reset();
sliderImages[current + 1].style.display = 'block';
current++;
}
prevArrow.addEventListener('click', () => {
if(current === 0 ) {
current = sliderImages.length;
}
prevSlide();
});
nextArrow.addEventListener('click', () => {
if(current === sliderImages.length - 1 ) {
current = -1
}
nextSlide();
});
startSlide()
No sorry I should have been more clear and included some html. I have 3 dots at the bottom of the slider. When slide one is the current image the first dot will have the css class added to it, when the second image is showing the second do will have the active class and the first dot wont any more. Hope that makes more sense?
<div class="indicator">
<span class="indicator__dot">&nbsp</span>
<span class="indicator__dot">&nbsp</span>
<span class="indicator__dot">&nbsp</span>
</div>
Haven't tested this so may have some bugs. setAnchor() function resets all the dots and add active class to the current dot.
setAnchor = () => {
for(let i = 0; i <dots.length; i++) {
sliderImages[i].classList.remove("active");
if(current === i){
sliderImages[i].classList.add("active");
}
}
}
startSlide = () => {
reset();
sliderImages[current].style.display = 'block'
setAnchor();
}
prevSlide = () => {
reset();
current -- ;
sliderImages[current].style.display = 'block';
setAnchor();
}
nextSlide = () => {
reset();
current++;
sliderImages[current].style.display = 'block';
setAnchor();
}

HTML5 Audio play two sounds in IOS

i want to play 2 sounds in ios and since it could not be done, i defined 2 audio objects.
i start playing the first sound and when want to play the second, i pause the first and wait till the second end, then i resume playing the first from the point it reached.
you can check the following code, if i remove the alert("test"); the first audio start playing from zero and so current time don't work!
kindly help.
Thanks,
var PlayedTime = 0; ; //in seconds
var AudioObj;
var audioType = '.mp3';
var isResume = false;
$(document).ready(function () {
if (!!AudioSound.canPlayType('audio/ogg') === true) {
audioType = '.ogg' //For firefox and others who do not support .mp3
}
AudioObj = document.getElementById('AudioSound');
document.getElementById('AudioSound').addEventListener('ended', function () {
resume();
});
});
function play1() {
AudioObj.src = "Images/Sound1" + audioType;
AudioObj.load();
}
function play2() {
PlayedTime = AudioObj.currentTime;
AudioObj.pause();
AudioObj.src = "Images/Sound2" + audioType;
AudioObj.load();
AudioObj.play();
}
function resume() {
isResume = true;
AudioObj.pause();
AudioObj.src = "Images/Sound1" + audioType;
AudioObj.load();
}
function JumpAudio() {
AudioObj.currentTime = 36;
}
function DataLoadedtoPlay() {
AudioObj.play();
if (isResume) {
isResume = false;
try {
alert("test");
AudioObj.currentTime = PlayedTime;
}
catch (e) {
alert("catch");
}
}
}
<div id="containerAud">
<audio id="AudioSound" onloadeddata="DataLoadedtoPlay()"></audio>
</div>
<input type = "button" onclick="play1()" value="click1"/>
<input type = "button" onclick="play2()" value="click2" />
<input type = "button" onclick="JumpAudio()" value="JumpAudio" />
</div>

Categories