Any way to create an infinite carousel effect?

74 Views Asked by At

could you help me create an infinite carousel effect? I have a way to do it is by restarting the image carousel checking if I reach the end of images and returning to 0 with " progress = (progress <= 0) ? 100 : 0;" but I don't like its effect, I would like that when I reach the end or almost the end of the items, images will always continue to be shown, that is, it will have images all the time both on the left and on the right without seeing that effect of restarting the carousel

     let progress = 50;
    let startX = 0;
    let active = 0;
    let isDown = false;
    const perView = 1
 
let totalScroll = 0
    let autoplayInterval;
        
        /*--------------------
        Contants
        --------------------*/
        const speedWheel = 0.02
        const speedDrag = -0.1
        
        /*--------------------
        Get Z
        --------------------*/
        const getZindex = (array, index) => (array.map((_, i) => (index === i) ? array.length : array.length - Math.abs(index - i)))
        
        /*--------------------
        Items
        --------------------*/
        const $items = document.querySelectorAll('.carousel-item')
        const $cursors = document.querySelectorAll('.cursor')
        
        const displayItems = (item, index, active) => {
          const zIndex = getZindex([...$items], active)[index]
          item.style.setProperty('--zIndex', zIndex)
          item.style.setProperty('--active', (index-active)/$items.length)


        }
        
        /*--------------------
        Animate
        --------------------*/
        const animate = () => {
          progress = Math.max(0, Math.min(progress, 100))
          active = Math.floor(progress/100*($items.length-1))
          
          $items.forEach((item, index) => displayItems(item, index, active))
        }
        animate()
        
        /*--------------------
        Click on Items
        --------------------*/
        $items.forEach((item, i) => {
          item.addEventListener('click', () => {
            progress = (i/$items.length) * 100 + 10
            animate()
          })
        })
    
const carousel = document.querySelector('.carousel-container');
const slides = document.querySelectorAll('.carousel-item');





    const totalItems = $items.length;

const autoPlay = () => {
    if (!isDown) {
        progress += 6; // Ajusta la velocidad del autoplay según lo desees
        if (progress >= 100) {
            active = totalItems - 1; // Establecer la última imagen como activa
            progress = 100; // Mantener el progreso al 100%
            animate();
            if (active === totalItems - 1) {
                setTimeout(() => {
             progress = (progress <= 0) ? 100 : 0;
                }, 1500); // Establece el tiempo para mostrar la última imagen antes de reiniciar
            }
        } else {
            animate();
        }
    }
};




    /* Iniciar autoplay */
    autoplayInterval = setInterval(autoPlay, 1000)
        /*--------------------
        Handlers
        --------------------*/
        const handleWheel = e => {
          const wheelProgress = e.deltaY * speedWheel
          progress = progress + wheelProgress
          animate()
        }
        
        const handleMouseMove = (e) => {
          if (e.type === 'mousemove') {
            $cursors.forEach(($cursor) => {
              $cursor.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`
            })
          }
          if (!isDown) return
          const x = e.clientX || (e.touches && e.touches[0].clientX) || 0
          const mouseProgress = (x - startX) * speedDrag
          progress = progress + mouseProgress
          startX = x
          animate()
        }
        
        const handleMouseDown = e => {
          isDown = true
          startX = e.clientX || (e.touches && e.touches[0].clientX) || 0
        }
        
        const handleMouseUp = () => {
          isDown = false
        }

        /*--------------------
        Listeners
        --------------------*/
        
        document.addEventListener('mousedown', handleMouseDown)
        document.addEventListener('mousemove', handleMouseMove)
        document.addEventListener('mouseup', handleMouseUp)
        document.addEventListener('touchstart', handleMouseDown)
        document.addEventListener('touchmove', handleMouseMove)
        document.addEventListener('touchend', handleMouseUp)
 

 
.carousel {
  position: relative;
  z-index: 1;
  height: 550px;
  overflow: hidden;
  pointer-events: none;
  background-image: url(img/Banner-NET-1.jpg);
  background-size: contain;
}

.carousel-item {
  --items: 10;
  --width: clamp(150px, 30vw, 250px);
  --height: clamp(150px, 40vw, 350px);
  --x: calc(var(--active) * 800%);
  --y: calc(var(--active) * 200%);
  --rot: calc(var(--active) * 120deg);
  --opacity: calc(var(--zIndex) / var(--items) * 3 - 2);
  overflow: hidden;
  position: absolute;
  z-index: var(--zIndex);
  width: var(--width);
  height: var(--height);
  margin: calc(var(--height) * -0.5) 0 0 calc(var(--width) * -0.5);
  border-radius: 10px;
  top: 50%;
  left: 50%;
  user-select: none;
  transform-origin: 0% 100%;
  box-shadow: 0 10px 50px 10px rgba(0, 0, 0, 0.5);
  background: black;
  pointer-events: all;
  transform: translate(var(--x), var(--y)) rotate(var(--rot));
  transition: transform 0.8s cubic-bezier(0, 0.02, 0, 1);
}
.carousel-item .carousel-box {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.8s cubic-bezier(0, 0.02, 0, 1);
  opacity: var(--opacity);
  font-family: "Orelo-sw-db", serif;
}
.carousel-item .carousel-box:before {
  content: "";
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.5));
}

.portfolio-item-link .full-image:before {
  z-index: -999;
  
}
.carousel-item .title {
  position: absolute;
  z-index: 1;
  color: #fff;
  bottom: 20px;
  left: 20px;
  transition: opacity 0.8s cubic-bezier(0, 0.02, 0, 1);
  font-size: clamp(20px, 3vw, 30px);
  text-shadow: 0 4px 4px rgba(0, 0, 0, 0.1);
}
.carousel-item .num {
  position: absolute;
  z-index: 1;
  color: #fff;
  top: 10px;
  left: 20px;
  transition: opacity 0.8s cubic-bezier(0, 0.02, 0, 1);
  font-size: clamp(20px, 10vw, 80px);
}
.carousel-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.layout {
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.layout:before {
  content: "";
  position: absolute;
  z-index: 1;
  top: 0;
  left: 90px;
  width: 10px;
  height: 100%;
  border: 1px solid #fff;
  border-top: none;
  border-bottom: none;
  opacity: 0.15;
}
.layout .box {
  position: absolute;
  bottom: 0;
  left: 30px;
  color: #fff;
  transform-origin: 0% 10%;
  transform: rotate(-90deg);
  font-size: 9px;
  line-height: 1.4;
  text-transform: uppercase;
  opacity: 0.4;
}








/*# sourceMappingURL=style.css.map */










.icono {
    position: absolute;
    top: 150px;
    left: 103px;
    color: #fff;
    border: solid 1px #fff;
    border-radius: 30px;
    padding: 5px;
    transition-property: all;
    transition-duration: 200ms;
    transition-timing-function: ease;
  z-index: 999;
}
.icono:hover {
    color: #413B52;
    border: solid 1px #fff;
    width: 50px;
    height: 50px;
    left: 103px;
    top: 147px;
    
}

@media (max-width: 767px) {
   .icono {
  position: absolute;
  top: 50% !important; /* Centrado vertical */
  left: 50% !important; /* Centrado horizontal */
  transform: translate(-50%, -50%) !important; /* Ajuste para centrar en ambas direcciones */
  color: #fff;
  border: solid 1px #fff;
  border-radius: 30px;
  padding: 5px;
  transition: all 200ms ease;
  z-index: 999;
}
.title {
  display: flex;
  align-items: center; /* Centrado vertical */
  justify-content: center; /* Centrado horizontal */
  /* Agrega estilos adicionales si es necesario */
}

.title h5 {
  margin: 0; /* Elimina el margen predeterminado del <h5> */
  /* Agrega estilos adicionales si es necesario */
}
.carousel-item .title {
  position: absolute;
  z-index: 1;
  color: #fff;
  bottom: 28% !important;
  left: 30% !important;
  transition: opacity 0.8s cubic-bezier(0, 0.02, 0, 1);
  font-size: clamp(20px, 3vw, 30px);
  text-shadow: 0 4px 4px rgba(0, 0, 0, 0.1);
}
.carousel-item {
  --items: 10;
  --width: clamp(190px, 30vw, 250px) !important;
  --height: clamp(230px, 40vw, 350px) !important;
  --x: calc(var(--active) * 800%);
  --y: calc(var(--active) * 200%);
  --rot: calc(var(--active) * 120deg);
  --opacity: calc(var(--zIndex) / var(--items) * 3 - 2);
  overflow: hidden;
  position: absolute;
  z-index: var(--zIndex);
  width: var(--width);
  height: var(--height);
  margin: calc(var(--height) * -0.5) 0 0 calc(var(--width) * -0.5);
  border-radius: 10px;
  top: 50%;
  left: 50%;
  user-select: none;
  transform-origin: 0% 100%;
  box-shadow: 0 10px 50px 10px rgba(0, 0, 0, 0.5);
  background: black;
  pointer-events: all;
  transform: translate(var(--x), var(--y)) rotate(var(--rot));
  transition: transform 0.8s cubic-bezier(0, 0.02, 0, 1);
}
  
}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
   
</head>
<body>
    
    <div class="carousel">
        
        <div class="carousel-item">
            
            <div class="carousel-box">
                <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                    <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
                  </svg></a>
                <div class="title"><h5>test text 01</h5></div>
                
                <img src="http://pruebas.significadosyletras.com/slider/img/zif.jpg" />
                
                
                
            </div>
        </div>
    
        <div class="carousel-item">
            
            <div class="carousel-box">
                <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                    <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
                  </svg></a>
                <div class="title"><h5>test text 02</h5></div>
                
                <img src="http://pruebas.significadosyletras.com/slider/img/zif.jpg" />
            </div>
    
        </div>
    
        <div class="carousel-item">
            <div class="carousel-box">
                <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                    <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
                  </svg></a>
                <div class="title"><h5>test text 03</h5></div>
                
                <img
                    src="http://pruebas.significadosyletras.com/slider/img/zif.jpg"
                />
            </div>
        </div>
    
        <div class="carousel-item">
            <div class="carousel-box">
                <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                    <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
                  </svg></a>
                <div class="title"><h5>test text 04</h5></div>
                
                <img src="http://pruebas.significadosyletras.com/slider/img/zif.jpg" />
            </div>
        </div>
    
        <div class="carousel-item">
            <div class="carousel-box">
                <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                    <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
                  </svg></a>
                <div class="title"><h5>test text 05</h5></div>
                
                <img src="http://pruebas.significadosyletras.com/slider/img/zif.jpg" />
                
            </div>
        </div>
    
        <div class="carousel-item">
            <a href="https://www.youtube.com/watch?v=i4OGOxjSflQ" target="_self" class="portfolio-item-link full-image" data-fancybox="thegem-portfolio" data-elementor-open-lightbox="no"><svg class="icono" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-player-play-filled" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
                <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
                <path d="M6 4v16a1 1 0 0 0 1.524 .852l13 -8a1 1 0 0 0 0 -1.704l-13 -8a1 1 0 0 0 -1.524 .852z" stroke-width="0" fill="currentColor" />
              </svg></a>
            <div class="carousel-box">
                <div class="title"><h5>test text 06</h5></div>
        
                <img src="http://pruebas.significadosyletras.com/slider/img/zif.jpg" />
            </div>
        </div>
    
        
    </div></body></html>

1

There are 1 best solutions below

1
Coco On

Marquee seems to work really well (HTML). Otherwise, you can animate the image to move from Point A to Point B, and then when offscreen teleport back to Point A, effectively mimicking an infinite carousel of images