Scriver
Scriver

Reputation: 45

How to make image slider respond to thumb swipe

Hi I am using the basic W3 slideshow layout but It is not very good for the mobile version of my site.

I searched very hard to find a solution to this but it's always download some plug-in to make it work or something that doesn't respond very well to swipes

$('.slider').on('touchstart', function(event) {
  const xClick = event.originalEvent.touches[0].pageX;
  
  $(this).one('touchmove', function(event) {
    const xMove = event.originalEvent.touches[0].pageX;
    const sensitivityInPx = 5;

    if (Math.floor(xClick - xMove) > sensitivityInPx) {
      $(this).slider('next');
    } 
    else if (Math.floor(xClick - xMove) < -sensitivityInPx) {
      $(this).slider('prev');
    }
  });
  
  $(this).on('touchend', function() {
    $(this).off('touchmove');
  });
});

let slideIndex = 1;
showSlides(slideIndex);

function plusSlides(n) {
  showSlides(slideIndex += n);
}

function currentSlide(n) {
  showSlides(slideIndex = n);
}

function showSlides(n) {
  let i;
  let slides = document.getElementsByClassName("mySlides");
  let dots = document.getElementsByClassName("dot");
  
  if (n > slides.length) {
    slideIndex = 1
  }
  
  if (n < 1) {
    slideIndex = slides.length
  }
  
  for (i = 0; i < slides.length; i++) {
    slides[i].style.display = "none";
  }
  
  for (i = 0; i < dots.length; i++) {
    dots[i].className = dots[i].className.replace(" active", "");
  }
  
  slides[slideIndex - 1].style.display = "block";
  dots[slideIndex - 1].className += " active";
}
* {
  box-sizing: border-box
}

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
}

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

.mySlides {
  display: none
}

img {
  vertical-align: middle;
}

/* Slideshow container */

.slideshow-container {
  padding: 10px;
  max-width: 1000px;
  position: relative;
  margin: auto;
  -webkit-overflow-scrolling: touch;
}

/* Next & previous buttons */

.prev,
.next {
  cursor: pointer;
  position: absolute;
  top: 50%;
  width: auto;
  padding: 16px;
  margin-top: -22px;
  color: white;
  font-weight: bold;
  font-size: 18px;
  transition: 0.6s ease;
  border-radius: 0 3px 3px 0;
  user-select: none;
}

/* Position the "next button" to the right */

.next {
  right: 0;
  border-radius: 3px 0 0 3px;
}

/* On hover, add a black background color with a little bit see-through */

.prev:hover,
.next:hover {
  background-color: rgba(0, 0, 0, 0.8);
}

/* Caption text */

.text {
  color: #f2f2f2;
  font-size: 15px;
  padding: 8px 12px;
  position: absolute;
  bottom: 8px;
  width: 100%;
  text-align: center;
}

/* Number text (1/3 etc) */

.numbertext {
  color: #f2f2f2;
  font-size: 12px;
  padding: 8px 12px;
  position: absolute;
  top: 0;
}

/* The dots/bullets/indicators */

.dot {
  cursor: pointer;
  height: 15px;
  width: 15px;
  margin: 0 2px;
  background-color: #bbb;
  border-radius: 50%;
  display: inline-block;
  transition: background-color 0.6s ease;
}

.active,
.dot:hover {
  background-color: #717171;
}

/* Fading animation */

.fade {
  animation-name: fade;
  animation-duration: 1.5s;
}

@keyframes fade {
  from {
    opacity: .4
  }
  to {
    opacity: 1
  }
}

/* On smaller screens, decrease text size */

@media only screen and (max-width: 300px) {
  .prev,
  .next,
  .text {
    font-size: 11px
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slider" class="slideshow-container">
  <!-- images -->
  <div class="mySlides fade">
    <!-- <div class="numbertext">1 / 3</div> -->
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
    <div class="text">Caption Text</div>
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <a class="prev" onclick="plusSlides(-1)">❮</a>
  <a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>

<div style="text-align:center">
  <!-- dots-->
  <span class="dot" onclick="currentSlide(1)"></span>
  <span class="dot" onclick="currentSlide(2)"></span>
  <span class="dot" onclick="currentSlide(3)"></span>
  <span class="dot" onclick="currentSlide(4)"></span>
</div>

Upvotes: 3

Views: 3997

Answers (2)

Scriver
Scriver

Reputation: 45

Even though this is not pure Js and it is a different approach

I found that flickity.js and css is good for mobile and it's just 2 ajax calls like jquery

https://flickity.metafizzy.co/api.html

<script src="//cdnjs.cloudflare.com/ajax/libs/flickity/1.0.0/flickity.pkgd.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/flickity/1.0.0/flickity.css">

HTML

<div class="carousel">
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
  <div class="carousel-cell"></div>
</div>

CSS

/* external css: flickity.css */

* { box-sizing: border-box; }

body { font-family: sans-serif; }

.carousel {
  background: #FAFAFA;
}

.carousel-cell {
  width: 28%;
  height: 200px;
  margin-right: 10px;
  background: #8C8;
  border-radius: 5px;
  counter-increment: carousel-cell;
}

/* cell number */
.carousel-cell:before {
  display: block;
  text-align: center;
  content: counter(carousel-cell);
  line-height: 200px;
  font-size: 80px;
  color: white;
}

.button {
  font-size: 22px;
}

.button-group {
  margin-bottom: 20px;
}

Js

// external js: flickity.pkgd.js

var flkty = new Flickity( '.carousel', {
  groupCells: true
});

var buttonGroup = document.querySelector('.button-group');
var buttons = buttonGroup.querySelectorAll('.button');
buttons = fizzyUIUtils.makeArray( buttons );

buttonGroup.addEventListener( 'click', function( event ) {
  // filter for button clicks
  if ( !matchesSelector( event.target, '.button' ) ) {
    return;
  }
  var index = buttons.indexOf( event.target );
  flkty.selectCell( index );
});

Upvotes: 1

biberman
biberman

Reputation: 5767

Like i wrote in the comments, you have two typos: $(this).one('touchmove and .slider, which has to be $(this).on('touchmove and #slider.


But the main problem is your function slider(), which isn't defined. But you can use the function plusSlides(), that you are already using for the next and prev buttons.

Furthermore the touchmove event is firing very often until the touchend event is fired. Therefor the function plusSlides() is called multiple times. To fix this, stop the touchmove event listener when the function plusSlides() is called.

Working example:

$('#slider').on('touchstart', function(event) {
  const xClick = event.originalEvent.touches[0].pageX;

  $(this).on('touchmove', function(event) {
    const xMove = event.originalEvent.touches[0].pageX;
    const sensitivityInPx = 5;

    if (Math.floor(xClick - xMove) > sensitivityInPx) {
      plusSlides(1);
      $(this).off('touchmove');
    } 
    else if (Math.floor(xClick - xMove) < -sensitivityInPx) {
      plusSlides(-1);
      $(this).off('touchmove');
    }
  });
});

let slideIndex = 1;
showSlides(slideIndex);

function plusSlides(n) {
  showSlides(slideIndex += n);
}

function currentSlide(n) {
  showSlides(slideIndex = n);
}

function showSlides(n) {
  let i;
  let slides = document.getElementsByClassName("mySlides");
  let dots = document.getElementsByClassName("dot");

  if (n > slides.length) {
    slideIndex = 1
  }
  if (n < 1) {
    slideIndex = slides.length
  }

  for (i = 0; i < slides.length; i++) {
    slides[i].style.display = "none";
  }

  for (i = 0; i < dots.length; i++) {
    dots[i].className = dots[i].className.replace(" active", "");
  }

  slides[slideIndex - 1].style.display = "block";
  dots[slideIndex - 1].className += " active";
}
* {
  box-sizing: border-box
}

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
}

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

.mySlides {
  display: none
}

img {
  vertical-align: middle;
}

/* Slideshow container */

.slideshow-container {
  padding: 10px;
  max-width: 1000px;
  position: relative;
  margin: auto;
  -webkit-overflow-scrolling: touch;
}

/* Next & previous buttons */

.prev,
.next {
  cursor: pointer;
  position: absolute;
  top: 50%;
  width: auto;
  padding: 16px;
  margin-top: -22px;
  color: white;
  font-weight: bold;
  font-size: 18px;
  transition: 0.6s ease;
  border-radius: 0 3px 3px 0;
  user-select: none;
}

/* Position the "next button" to the right */

.next {
  right: 0;
  border-radius: 3px 0 0 3px;
}

/* On hover, add a black background color with a little bit see-through */

.prev:hover,
.next:hover {
  background-color: rgba(0, 0, 0, 0.8);
}

/* Caption text */

.text {
  color: #f2f2f2;
  font-size: 15px;
  padding: 8px 12px;
  position: absolute;
  bottom: 8px;
  width: 100%;
  text-align: center;
}

/* Number text (1/3 etc) */

.numbertext {
  color: #f2f2f2;
  font-size: 12px;
  padding: 8px 12px;
  position: absolute;
  top: 0;
}

/* The dots/bullets/indicators */

.dot {
  cursor: pointer;
  height: 15px;
  width: 15px;
  margin: 0 2px;
  background-color: #bbb;
  border-radius: 50%;
  display: inline-block;
  transition: background-color 0.6s ease;
}

.active,
.dot:hover {
  background-color: #717171;
}

/* Fading animation */

.fade {
  animation-name: fade;
  animation-duration: 1.5s;
}

@keyframes fade {
  from {
    opacity: .4
  }
  to {
    opacity: 1
  }
}

/* On smaller screens, decrease text size */

@media only screen and (max-width: 300px) {
  .prev,
  .next,
  .text {
    font-size: 11px
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slider" class="slideshow-container">
  <!-- images -->

  <div class="mySlides fade">
    <!-- <div class="numbertext">1 / 3</div> -->
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
    <div class="text">Caption Text</div>
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <div class="mySlides fade">
    <img src="http://upload.wikimedia.org/wikipedia/commons/7/73/Lion_waiting_in_Namibia.jpg" style="width:100%">
  </div>

  <a class="prev" onclick="plusSlides(-1)">❮</a>
  <a class="next" onclick="plusSlides(1)">❯</a>

</div>
<br>

<div style="text-align:center">
  <!-- dots-->
  <span class="dot" onclick="currentSlide(1)"></span>
  <span class="dot" onclick="currentSlide(2)"></span>
  <span class="dot" onclick="currentSlide(3)"></span>
  <span class="dot" onclick="currentSlide(4)"></span>
</div>

Upvotes: 0

Related Questions