0

I'm making a photo slider using HTML, CSS and JS. It has an autoplay function, navigation arrows and dots. The direction of the slide animation is reversed based on the corresponding arrows/dots, and the timer is reset on each slide. I'm currently trying to add a "pause on hover" function, but it doesn't pause the timer but resets the timer.

For example, the slider speed is currently set to 3000ms. When the cursor hovers over .elements at 2000ms, I need it to pause the timer. And when the cursor leaves .elements, I need the timer to count down the remaining 1000ms and then move on to the next slide. Could you please help me with this?

var timeout;

function setDirection(d) {
  document.querySelector('.slider').style.setProperty('--direction', d);
}
setDirection(1);
var slider = document.getElementsByClassName("slider")[0];
var sliderDots = Array.prototype.slice.call(document.getElementsByClassName("dots")[0].children);
var sliderContents = Array.prototype.slice.call(document.getElementsByClassName("elements")[0].children);
var sliderArrowLeft = document.getElementsByClassName("arrow-left")[0];
var sliderArrowRight = document.getElementsByClassName("arrow-right")[0];
var sliderSpeed = 3000,
  currentSlide = 0,
  currentActive = 0,
  sliderTimer = 0;

let elements = document.querySelector('.elements');
elements.addEventListener('mouseover', function() {
  clearTimeout(sliderTimer);
});

elements.addEventListener('mouseout', function() {
  playSlide(currentSlide);
});

function playSlide(slide, d) {
  if (!(d === undefined)) {
    direction = d;
    setDirection(d);

    // Force it forwards after it's done:
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      setDirection(1);
    }, 1000)
  }
  for (var k = 0; k < sliderDots.length; k++) {
    sliderContents[k].classList.remove("active");
    sliderContents[k].classList.remove("inactive");
    sliderDots[k].classList.remove("active");
  }
  if (slide < 0) {
    slide = currentSlide = sliderContents.length - 1;
  }
  if (slide > sliderContents.length - 1) {
    slide = currentSlide = 0;
  }
  if (currentActive != currentSlide) {
    sliderContents[currentActive].classList.add("inactive");
  }
  sliderContents[slide].classList.add("active");
  sliderDots[slide].classList.add("active");
  currentActive = currentSlide;
  clearTimeout(sliderTimer);
  sliderTimer = setTimeout(function() {
    playSlide(currentSlide += 1);
  }, sliderSpeed)
}
sliderArrowLeft.addEventListener("click", function() {
  playSlide(currentSlide -= 1, -1);
})
sliderArrowRight.addEventListener("click", function() {
  playSlide(currentSlide += 1, 1);
})
for (var l = 0; l < sliderDots.length; l++) {
  sliderDots[l].addEventListener("click", function() {
    let d = sliderDots.indexOf(this) - currentSlide
    playSlide(currentSlide = sliderDots.indexOf(this), Math.sign(d));
  })
}
playSlide(currentSlide);
.slider {
  overflow: hidden;
  position: relative;
}

.contents {
  width: 100%;
  height: 200px;
  position: relative;
  overflow: hidden;
}

.arrow-left,
.arrow-right {
  width: 50px;
  height: 50px;
  bottom: 0;
  cursor: pointer;
  display: block;
  text-align: center;
  line-height: 50px;
  background: rgb(200, 200, 200);
  position: absolute;
  z-index: 2;
}

.arrow-left {
  left: 0;
}

.arrow-right {
  right: 0;
}

.dots {
  height: 14px;
  bottom: 0;
  left: 50%;
  font-size: 0;
  text-align: right;
  position: absolute;
  z-index: 2;
  transform: translateX(-50%);
}

.dot {
  width: 12px;
  height: 12px;
  margin-left: 5px;
  margin-right: 5px;
  display: inline-block;
  cursor: pointer;
  border-style: solid;
  border-width: 1px;
  border-color: rgb(100, 100, 100);
}

.dot.active {
  background: rgb(200, 200, 200);
}

.elements {
  width: 100%;
  overflow: hidden;
  transform: translate(0px);
}

.image {
  width: 100%;
  height: 100px;
  top: 0;
  position: absolute;
  opacity: 0;
}

.image span {
  width: 100%;
  height: 100px;
  text-align: center;
  line-height: 100px;
  display: block;
  background: rgb(200, 200, 200);
}

.image.active {
  position: relative;
  z-index: 1;
  opacity: 1;
}

.image.inactive {
  z-index: -3;
  opacity: 1;
}

.image.active span {
  animation: show .5s ease-in-out forwards;
}

.image.inactive span {
  animation: hide .5s ease-in-out forwards;
}

@keyframes show {
  0% {
    transform: translateX(calc(var(--direction)*100%));
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes hide {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(calc(-1*var(--direction)*100%));
  }
}
<div class="slider">
  <div class="contents">
    <div class="arrow-left">prev</div>
    <div class="arrow-right">next</div>
    <div class="dots">
      <li class="dot"></li>
      <li class="dot"></li>
      <li class="dot"></li>
    </div>
    <div class="elements">
      <div class="image"><span>image 1</span></div>
      <div class="image"><span>image 2</span></div>
      <div class="image"><span>image 3</span></div>
    </div>
  </div>
</div>
tez
  • 117
  • 1
  • 8
  • So you will need to _create_ a new timeout then, when the mouse cursor leaves the element again. Create a new `Date` instance when you start the timer, and a new one when you hover the element - and calculate the difference in ms. 3000ms minus that difference, are the value you need to set your new timeout with. – CBroe Aug 28 '23 at 10:53
  • related: https://stackoverflow.com/questions/3969475/javascript-pause-settimeout – GrafiCode Aug 28 '23 at 11:27
  • Thank you for the ideas. In theory they might be the solution I'm looking for, but in practice I still can't manage to adapt the method to my own slider :( – tez Aug 28 '23 at 14:44

1 Answers1

0

Adjust the css according to you, I have written some css for both of us to understand so that the result looks healthy and clean to solve your question. I am giving you a slider ready. I provide you the code of HTML, CSS and JS.

var timeout;
        var sliderDots = Array.from(document.getElementsByClassName("dot"));
        var sliderContents = Array.from(document.getElementsByClassName("image"));
        var sliderArrowLeft = document.querySelector(".arrow-left");
        var sliderArrowRight = document.querySelector(".arrow-right");
        var sliderSpeed = 3000;
        var currentSlide = 0;
        var sliderTimer = 0;

        var elements = document.querySelector('.elements');
        var isPaused = false;

        elements.addEventListener('mouseover', function () {
            clearTimeout(sliderTimer);
            isPaused = true;
        });

        elements.addEventListener('mouseout', function () {
            isPaused = false;
            sliderTimer = setTimeout(function () {
                playSlide(currentSlide + 1);
            }, sliderSpeed);
        });

        function playSlide(slide) {
            for (var k = 0; k < sliderDots.length; k++) {
                sliderContents[k].classList.remove("active");
                sliderDots[k].classList.remove("active");
            }
            if (slide < 0) {
                slide = currentSlide = sliderContents.length - 1;
            }
            if (slide > sliderContents.length - 1) {
                slide = currentSlide = 0;
            }
            // Update the currentSlide
            currentSlide = slide;
            // Add the "active" class to the current slide and dot
            sliderContents[currentSlide].classList.add("active");
            sliderDots[currentSlide].classList.add("active");

            if (!isPaused) {
                clearTimeout(sliderTimer);
                sliderTimer = setTimeout(function () {
                    playSlide(currentSlide + 1);
                }, sliderSpeed);
            }
        }

        sliderArrowLeft.addEventListener("click", function () {
            playSlide(currentSlide - 1);
        });

        sliderArrowRight.addEventListener("click", function () {
            playSlide(currentSlide + 1);
        });

        for (var l = 0; l < sliderDots.length; l++) {
            sliderDots[l].addEventListener("click", function () {
                playSlide(sliderDots.indexOf(this));
            });
        }

        playSlide(currentSlide);
body,
        ul {
            margin: 0;
            padding: 0;
        }

        /* Global styles */
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
        }

        /* Slider container */
        .slider {
            position: relative;
            max-width: 600px;
            margin: 0 auto;
            overflow: hidden;
            border: 1px solid #ccc;
        }

        /* Slider contents */
        .contents {
            position: relative;
        }

        /* Slide images */
        .image {
            display: none;
        }

        .image.active {
            display: block;
        }

        /* Slide navigation arrows */
        .arrow-left,
        .arrow-right {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            cursor: pointer;
            padding: 8px;
            background-color: rgba(0, 0, 0, 0.3);
            color: white;
            border-radius: 50%;
        }

        .arrow-left {
            left: 10px;
        }

        .arrow-right {
            right: 10px;
        }

        /* Slide navigation dots */
        .dots {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            list-style: none;
            display: flex;
            padding: 0;
        }

        .dot {
            width: 12px;
            height: 12px;
            margin: 0 6px;
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 50%;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .dot.active {
            background-color: rgba(0, 0, 0, 0.9);
        }
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Slide</title>
</head>

<body>

    <div class="slider">
        <div class="contents">
            <div class="arrow-left">prev</div>
            <div class="arrow-right">next</div>
            <ul class="dots">
                <li class="dot"></li>
                <li class="dot"></li>
                <li class="dot"></li>
            </ul>
            <div class="elements">
                <div class="image active"><img src="https://dummyimage.com/600x400/aaa/fff&text=1" alt="Image 1"></div>
                <div class="image"><img src="https://dummyimage.com/600x400/aaa/fff&text=2" alt="Image 2"></div>
                <div class="image"><img src="https://dummyimage.com/600x400/aaa/fff&text=3" alt="Image 3"></div>
            </div>
        </div>
    </div>
</body>

</html>
  • Thank you for your effort! Could you please add the rest of my codes, so everyone can see your solution in action? – tez Aug 28 '23 at 19:13
  • I will try my best to help you. – Deep Javiya Aug 29 '23 at 20:07
  • Thanks, I'm looking for it. Once your solution works stable, I'll click on the accepted answer button gladly. – tez Aug 30 '23 at 08:44
  • check edited code. – Deep Javiya Aug 31 '23 at 03:18
  • Please correct me if I'm wrong but mouse-hover resets the timer in your code -- it doesn't pause. So your method does the same thing with the code I provided, and sliding direction function seems missing – tez Aug 31 '23 at 05:26
  • check edited code. – Deep Javiya Sep 01 '23 at 06:21
  • I'm thankful for your time and effort, but mouse-hover still "resets" the timer, not pause... Additionally, my rotation determining function and ltr/rtl sliding animations seems missing... When adding a new feature, I think it's important to avoid breaking the existing features since it'll not be easy to fix them later. – tez Sep 01 '23 at 08:35