newbiefatcoder
newbiefatcoder

Reputation: 45

How can I disable touch events on certain elements in a carousel?

I am trying to build a carousel for the header section of a website. I am trying to prevent touch events that enable scrolling past the first element and the last element but I have been unable to do this. I looked up some past answers and tried to use the getBoundingClientRect to get the first element's width and prevent scrolling but this disables the whole scrolling feature.

HTML and PHP. The website is a WordPress website so I had to query the carousel's information from the database.

const prev = document.querySelector('.prev');
const next = document.querySelector('.next');
const track = document.querySelector('.track');
const carouselWidth = document.querySelector('.carousel-container').getBoundingClientRect().width;

let index = 0;
let initialPosition = null;
let moving = false;
let transform = 0;
next.addEventListener('click', () => {
  index++;
  prev.classList.add('show');
  track.style.transform = `translateX(-${index * carouselWidth}px)`;
  if (track.offsetWidth - (index * carouselWidth) < carouselWidth) {
    next.classList.add('hide');
  }
});

prev.addEventListener('click', () => {
  index--;
  next.classList.remove('hide');
  if (index === 0) {
    prev.classList.remove('show');
  }
  track.style.transform = `translateX(-${index * carouselWidth}px)`
})
const gestureStart = (e) => {
  initialPosition = e.pageX;
  moving = true;
  const transformMatrix = window.getComputedStyle(track).getPropertyValue('transform');
  if (transformMatrix !== 'none') {
    transform = parseInt(transformMatrix.split(',')[4].trim());
  }
  prev.classList.add('show');
}

const gestureMove = (e) => {
  if (moving) {
    const currentPosition = e.pageX;
    const diff = currentPosition - initialPosition;
    track.style.transform = `translateX(${transform + diff}px)`;

  }
};

const gestureEnd = (e) => {
  moving = false;
}

if (window.PointerEvent) {
  window.addEventListener('pointerdown', gestureStart);

  window.addEventListener('pointermove', gestureMove);

  window.addEventListener('pointerup', gestureEnd);
} else {
  window.addEventListener('touchdown', gestureStart);

  window.addEventListener('touchmove', gestureMove);

  window.addEventListener('touchup', gestureEnd);

  window.addEventListener('mousedown', gestureStart);

  window.addEventListener('mousemove', gestureMove);

  window.addEventListener('mouseup', gestureEnd);
}
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.slider-container {
  background-color: #fff;
  border-bottom: 1px solid #d0d0d0;
  display: block;
  height: 120px;
  overflow: hidden;
  padding: 0;
}

.slider-header {
  line-height: 8px;
  margin: 10px 0 0;
  padding: 0 0 0 15px;
  text-transform: uppercase;
}

.slider-header:before {
  background-color: #d0d0d0;
  content: '';
  display: block;
  height: 1px;
  margin-right: -20px;
  position: relative;
  top: 6px;
}

.slider-header_text {
  background-color: #fff;
  display: inline-block;
  padding: 0 10px 0 0;
  position: relative;
}

.slider {
  position: relative;
}

button {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid #aaa;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background-color: #F9E929;
  cursor: pointer;
}

.carousel-container {
  width: 1280px;
  margin: auto;
  min-height: 100px;
  position: relative;
}

.carousel-container .carousel-inner {
  overflow: hidden;
}

.carousel-container .track {
  display: inline-flex;
  transition: transform 0.5s;
  touch-action: none;
}

.carousel-container .track .card-container {
  width: 256px;
  height: 100px;
  padding-right: 5px;
}

.carousel-container .track .card-container .card {
  border-right: 1px solid #ccc;
  display: flex;
  justify-content: space-around;
  margin-top: 20px;
  text-decoration: none;
  color: black;
}

.nav .prev {
  left: -30px;
  display: none;
}

.nav .prev.show {
  display: block;
}

.nav .next {
  right: -30px;
}

.nav .next.hide {
  display: none;
}

.card .img img {
  height: auto;
  width: auto;
  max-width: 88px;
  max-height: 59px;
}

.card .info h5 {
  padding-left: 5px;
  max-width: 150px;
}

@media (min-width: 768px) and (max-width: 1024px) {
  .button {
    display: none;
  }
  .carousel-container {
    width: 100vw;
  }
  .carousel-container .track .card-container {
    width: 25vw;
  }
}

@media(max-width: 500px) {
  .slider-container {
    border-bottom: none;
    height: 200px;
    margin-bottom: 50px;
  }
  .slider-header {
    display: none;
  }
  button {
    display: none;
  }
  .carousel-container {
    width: 100vw;
    min-height: 200px;
  }
  .carousel-container .track .card-container {
    width: 40vw;
    height: 200px;
  }
  .card .img img {
    width: 100%;
    height: 100%;
    position: relative;
  }
  .carousel-container .track .card-container .card {
    border-right: none;
    display: block;
    position: relative;
    margin-top: 20px;
    margin-left: 5px;
  }
  .card .info h5 {
    padding-left: 0;
    max-width: 100%;
    font-weight: 700;
  }
}
<div class="slider-container">
  <h4 class="slider-header">
    <span class="slider-header_text">Trending</span>
  </h4>

  <div class="slider">

    <div class="carousel-container">
      <div class="carousel-inner">
        <div class="track">
          <?php 
    global $wpdb;               
    $query = new WP_Query(array(
    'posts_per_page' => 12,
    'category_name' => 'posts',
));
  $posts =  $query -> posts;
  foreach ($posts as $post) {
 
  echo '
        <div class="card-container">
        <a href="'.$post->guid.'" class="card">
            <div class="img">
             <img src="'.get_the_post_thumbnail_url( $post -> ID, 'thumbnail' ).'" alt="">
            </div>
            <div class="info">
               <h5>'.$post->post_title.'</h5>
            </div>
          </a>
         </div>';
  }
   
                    
?>

        </div>
      </div>
      <div class="nav">
        <button class="prev">
       <i class="fas fa-angle-left"></i>
      </button>
        <button class="next">
       <i class="fas fa-angle-right"></i>
      </button>
      </div>
    </div>
  </div>
</div>

I already did this in my local environment before I moved it online using purely HTML, CSS and Javascript. I posted the code on jsfiddle. It could be accessed through this link https://jsfiddle.net/jqs62tp1/.

Upvotes: 1

Views: 2176

Answers (1)

Sergio Gabriel Fruto
Sergio Gabriel Fruto

Reputation: 331

Not sure if this is exactly what you need but you could try disabling touch-events via CSS:

/* styles applied to all card-containers except the first and last */
.card-container:not(:first-child),
.card-container:not(:last-child) {
  touch-action: none;
}

More details https://css-tricks.com/almanac/properties/t/touch-action/

Upvotes: 1

Related Questions