how to get slide indicator to match current slide? - javascript

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();
}

Related

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;
}
}

Vanilla JS image slideshow play/pause button

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;
});

Autoplay not working on my Javascript Slider

My goal is to coding a slider in Javascript, with a Class inside. But I meet 2 issues :
the Autoplay does not work
if I click on the Pause Button, and then click again on the play button, the autoplay does not work either
The HTML page is located there :
http://p4547.phpnet.org/bikes/slider.html
Here is my Javascript code :
class Diaporama {
constructor() {
this.controls = document.querySelectorAll('.controls');
this.slides = document.querySelectorAll('#diaporama .slide');
this.currentSlide = 0;
this.n = null;
this.playing = true;
this.pauseButton = document.getElementById('pause');
this.next = document.getElementById('next');
this.previous = document.getElementById('previous');
}
// Afficher les boutons previous, play, pause, next :
controlling() {
for(let i=0; i < this.controls.length; i++){
this.controls[i].style.display = 'inline-block';
}
}
// Slider Automatique :
goToSlide(n) {
this.slides[this.currentSlide].className = 'slide';
this.currentSlide = (n + this.slides.length)%this.slides.length;
this.slides[this.currentSlide].className = 'slide showing';
console.log(this.currentSlide);
}
nextSlide() {
this.goToSlide(this.currentSlide + 1);
}
previousSlide() {
this.goToSlide(this.currentSlide - 1);
}
slideInterval() {
setInterval(this.nextSlide,5000);
}
pauseSlideshow() {
this.pauseButton.innerHTML = '<i class="fas fa-play"></i>';
this.playing = false;
clearInterval(this.slideInterval);
}
playSlideshow() {
this.pauseButton.innerHTML = '<i class="fas fa-pause"></i>';
this.playing = true;
this.slideInterval = setInterval(this.nextSlide,5000);
}
nextItem() {
next.onclick = () => {
this.pauseSlideshow();
this.nextSlide();
}
}
previousItem() {
previous.onclick = () => {
this.pauseSlideshow();
this.previousSlide();
}
}
// Changement de slide par les touches du clavier :
clickKeyboard() {
document.addEventListener("keydown", ({keyCode}) => {
if(keyCode === 37){
this.nextSlide();
}
else if(keyCode === 39){
this.previousSlide();
}
})
}
};
let slider = new Diaporama();
slider.controlling();
slider.goToSlide(0);
slider.nextSlide();
slider.previousSlide();
slider.pauseSlideshow();
slider.playSlideshow();
slider.nextItem();
slider.previousItem();
slider.clickKeyboard();
This issue is inside playslideShow. When it calls this.nextSlide inside setInterval, the scope of this has changed. this refers to the window.
You can use bind() in this case, to make sure it refers to the slider object:
playSlideshow() {
this.pauseButton.innerHTML = '<i class="fas fa-pause"></i>';
this.playing = true;
this.slideInterval = setInterval(this.nextSlide.bind(this),5000);
}
Oh no, sorry, I found out why my Pause button was bugging.
I just added a new function :
restart() {
this.pauseButton.onclick = () => {
if(this.playing){ this.pauseSlideshow(); }
else{ this.playSlideshow(); }
}
}
It works fine now !

JavaScript: Change text color depending on video.currentTime

I have created navigation buttons for my video, some sort of timestamps that allow a user to jump to a certain moment in the video on click. The buttons change their color whenever they are clicked and the value of video.currentTime is in a particular range. When one button is red, the rest must be white ofcourse.
Take a look at my codepen: https://codepen.io/anon/pen/VRZPEP
My solution does work. However, I feel like it's too complicated and the feature could be done much simpler and with less code.
The important bit of javascript is under the //VIDEO NAV BUTTON FUNCTION header.
I'm just wondering if there's any way I could get rid of the changeToWhite() function? For example, by using some method making the button red only when the video.currentTime finds itself within a particular range?
var DOMstrings = {
nav_btn: document.querySelector('.navbar-button'),
nav_btn_mobile: document.querySelector('.navbar-toggler'),
nav_list: document.querySelector('#wrapper-for-list'),
//video
video: document.querySelector('#myVideo'),
//video-nav-buttons
nav_btn_1: document.querySelector('.video-nav h1:nth-child(1)'),
nav_btn_2: document.querySelector('.video-nav h1:nth-child(2)'),
nav_btn_3: document.querySelector('.video-nav h1:nth-child(3)'),
nav_btn_4: document.querySelector('.video-nav h1:nth-child(4)'),
nav_btn_5: document.querySelector('.video-nav h1:nth-child(5)')
}
//VIDEO NAV BUTTON FUNCTION
var navigateVideo = function() {
var video_nav = [DOMstrings.nav_btn_1, DOMstrings.nav_btn_2, DOMstrings.nav_btn_3, DOMstrings.nav_btn_4, DOMstrings.nav_btn_5]
var setTime = function(time) {
DOMstrings.video.currentTime = time;
};
var changeToWhite = function() {
video_nav.forEach(function(cur) {
cur.style.color = "white";
});
};
DOMstrings.video.addEventListener('timeupdate', function() {
var cur = DOMstrings.video.currentTime;
if (cur >= 0 && cur < 5) {
changeToWhite();
DOMstrings.nav_btn_1.style.color = "red";
} else if (cur > 5 && cur < 10) {
changeToWhite();
DOMstrings.nav_btn_2.style.color = "red";
} else if (cur > 10 && cur < 15) {
changeToWhite();
DOMstrings.nav_btn_3.style.color = "red";
} else if (cur > 15 && cur < 20) {
changeToWhite();
DOMstrings.nav_btn_4.style.color = "red";
} else if (cur > 25) {
changeToWhite();
DOMstrings.nav_btn_5.style.color = "red";
}
});
DOMstrings.nav_btn_1.addEventListener('click', function(e) {
setTime(0);
changeToWhite();
e.target.style.color = "red";
});
DOMstrings.nav_btn_2.addEventListener('click', function(e) {
setTime(15);
changeToWhite();
e.target.style.color = "red";
});
DOMstrings.nav_btn_3.addEventListener('click', function(e) {
setTime(30);
changeToWhite();
e.target.style.color = "red";
});
DOMstrings.nav_btn_4.addEventListener('click', function(e) {
setTime(45);
changeToWhite();
e.target.style.color = "red";
});
DOMstrings.nav_btn_5.addEventListener('click', function(e) {
setTime(60);
changeToWhite();
e.target.style.color = "red";
});
};
You could simplify this a little by renaming changeToWhite() to changeToRed(button):
const changeToRed = (button) => {
video_nav.forEach(cur => {
button.style.color = (cur === button) ? 'red' : 'white';
})
}
Then pass in each button when you call it:
changeToRed(DOMstrings.nav_btn_1);
// Previously:
// changeToWhite();
// DOMstrings.nav_btn_1.style.color = "red";
A few other things: You could make a single function that takes in a time in seconds instead of repeating the same function 5 times:
function handleClick(seconds) {
return function(e) {
setTime(seconds);
changeToRed(e.target);
}
}
DOMstrings.nav_btn_1.addEventListener('click', handleClick(0));
DOMstrings.nav_btn_2.addEventListener('click', handleClick(15));
DOMstrings.nav_btn_3.addEventListener('click', handleClick(30));
...etc
You could also get rid of the if/else block by doing this instead:
const cur = DOMstrings.video.currentTime;
// Divide the current time by 5 and round down, so 0-4 seconds
// would use index 0 (nav_btn_1), 5-9 seconds would use index
// 1 (nav_btn_2), etc
const buttonIndex = Math.floor(cur / 5);
changeToRed(video_nav[buttonIndex]);
You can consolidate logic in the timeUpdate listener, and you could also eliminate much repetition in the click listeners by replacing them all with a single click listener on the buttons' parent element. (This works because of event bubbling.) Altogether, it might look something like:
// Selectors
const video = document.querySelector("#myVideo");
const videoNav = document.querySelector(".video-nav");
const buttons = document.querySelectorAll(".video-nav button");
//Bindings
video.addEventListener("timeupdate", updateTime);
videoNav.addEventListener("click", conditionallySetTime);
//Listeners
function updateTime(event){
const time = event.target.time;
buttons.forEach(function(button, index){
button.style.color = index == Math.floor(time/15) ? "red" : "white"
});
}
function conditionallySetTime(event){
if(event.target.tagName == button){ // Now we care about this click
buttons.forEach(function(button, index){
if(event.target == button){
button.style.color = "red";
setTime(index * 15); // If 1st button is 0, 2nd is 15, etc.
}
else {
button.style.color = "white";
}
}
}
}

Js and Divs, (even <div> is difference)

I Have find a javascript code that works perfectly for showing a DIV.
but this code works only for showing one div for each page.
i want to include many DIVS for hiding and showing in the same page.
I was try to replace the div id and show/hide span id with a rundom php number for each include, but still is not working.
so how i have to do it?
the JS code:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Check out the Fiddle, you can edit code based on your needs ;)
$(function() {
$('.sub-nav li a').each(function() {
$(this).click(function() {
var category = $(this).data('cat');
$('.'+category).addClass('active').siblings('div').removeClass('active');
});
});
});
finaly i found my self:
<a class="showhide">AAA</a>
<div>show me / hide me</div>
<a class="showhide">BBB</a>
<div>show me / hide me</div>
js
$('.showhide').click(function(e) {
$(this).next().slideToggle();
e.preventDefault(); // Stop navigation
});
$('div').hide();
Am just posting this in case someone was trying to answer.

Categories