So I’m attempting to make a custom progress bar that splits into multiple bars depending on the number of slides and progresses through each synced with the duration of the slide speed and slide duration.
Issue: While the bar does progress, the timing slowly goes off until it’s entirely out of sync with the slide changes. I know it is likely to do with the calculation for the progress duration, but I’m not sure how I could calculate this differently to keep it in sync.
JS
// homepage carousel
let autoPlayDelay = 1500;
const mySwiper = new Swiper('.vertical-swiper', {
slidesPerView: 1,
spaceBetween: 0,
mousewheel: false,
autoplay: {
delay: autoPlayDelay
},
keyboard: true,
loop: false,
direction: 'vertical',
speed: 1500,
height: "465",
navigation: {
nextEl: '.swiper-btn-next',
prevEl: '.swiper-btn-prev',
},
});
let progress = document.querySelector('.swiper-progress-bar .progress');
const progressSections = document.querySelector('.swiper-progress-bar .progress-sections');
let slidersCount = mySwiper.params.loop ? mySwiper.slides.length - 2 : mySwiper.slides.length;
let widthParts = 100 / slidersCount;
function initProgressBar() {
let calcProgress = (slidersCount - 1) * (autoPlayDelay + mySwiper.params.speed);
calcProgress += autoPlayDelay;
progress.style.width = '0%';
progress.classList.remove('stopped');
progress.animate([{
width: '0%'
}, {
width: '100%'
}], calcProgress, 'linear');
}
initProgressBar();
for (let i = 0; i < slidersCount; i++) {
const span = document.createElement('span');
progressSections.appendChild(span);
}
// Cache DOM queries
const activeHeader = document.querySelector('.header-text');
const activeEyebrow = document.querySelector('.eyebrow-text');
function updateSlide(index) {
const slide = mySwiper.slides[index];
const collectionsEyebrow = slide.querySelector('.slide__eyebrow');
const collectionsHeader = slide.querySelector('.slide__heading');
if (activeHeader && activeEyebrow && collectionsEyebrow && collectionsHeader) {
// Slide up
activeHeader.classList.add('is--move');
activeEyebrow.classList.add('is--move');
// Replace text
setTimeout(() => {
activeHeader.textContent = collectionsHeader.textContent;
activeEyebrow.textContent = collectionsEyebrow.textContent;
}, 300);
// Slide down
setTimeout(() => {
activeHeader.classList.remove('is--move');
activeEyebrow.classList.remove('is--move');
}, 400);
}
}
window.addEventListener('load', function() {
// Call update header & eyebrow on page load
const activeIndex = mySwiper.activeIndex;
updateSlide(activeIndex);
});
// Call updateSlide function on slide change
mySwiper.on('slideChange', function() {
const activeIndex = mySwiper.activeIndex;
updateSlide(activeIndex);
// update slidersCount and widthParts
slidersCount = mySwiper.params.loop ? mySwiper.slides.length - 2 : mySwiper.slides.length;
widthParts = 100 / slidersCount;
let progress = document.querySelector('.swiper-progress-bar .progress');
// Calculate progress bar width based on current slide index and autoplay delay
const slideDelay = mySwiper.params.autoplay.delay;
const progressWidth = (activeIndex + 1) * widthParts;
const progressTime = (activeIndex + 1) * slideDelay;
if ((this.progress === -0 || (this.progress === 1 && this.params.loop)) && !progress.parentElement.classList.contains('stopped')) {
progress.style.width = '0';
if (this.activeIndex === 0) {
initProgressBar();
}
}
/* if (progress.parentElement.classList.contains('stopped')) {
progress.animate(
[
{ width: progress.style.width },
{ width: progressWidth + '%' }
],
{
duration: progressTime,
easing: 'linear'
}
);
} */
if (progress.parentElement.classList.contains('stopped')) {
const progressWidth = Math.round(widthParts * (mySwiper.activeIndex + 1));
progress.animate({
width: progressWidth + '%'
},
mySwiper.params.speed,
'linear'
);
}
});
mySwiper.on('touchMove', function() {
const progress = document.querySelector('.swiper-progress-bar .progress');
progress.style.animationPlayState = 'paused';
progress.parentElement.classList.add('stopped');
});
mySwiper.on('beforeSlideChangeStart', function() {
const slide = this.el.querySelector('.swiper-slide');
const slideImg = slide.querySelector('.img-container img');
const setClasses = !slide.classList.contains('swiper-slide-active');
setClass(slideImg, 'swiper-slide-active', 'remove');
if (setClasses) {
slide.classList.toggle('swiper-slide-active');
this.el.querySelector('.swiper-slide').classList.toggle('expand-img');
}
});
function setClass(el, className, fnName) {
el.classList[fnName](className);
}