JavaScript Rotating Image Carousel

JavaScript Rotating Image Carousel
Project: WIP: Rotating 3D Card Carousel
Author: James
Edit Online: View on CodePen
License: MIT

This code snippet helps you to create a rotating image carousel using javascript. It creates a 3D carousel of cards that can be rotated clockwise or counterclockwise by clicking on buttons. The code also calculates the necessary transforms based on the number of cards in the carousel and the size of the container to ensure that the cards are evenly spaced and centered. They can be used hidden on smaller viewports, as shown below, with optional display utilities

Now it’s time to create our project.

How to Create JavaScript Rotating Image Carousel

Create the HTML structure for the image carousel as follows:

<!--<pre id="debug1"></pre>
<pre id="debug2"></pre>-->
<p>Content before... You can't just have your characters announce how they feel. That makes me feel angry! Ah, the 'Breakfast Club' soundtrack! I can't wait til I'm old enough to feel ways about stuff! No! Don't jump! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife holding up? …To shreds, you say.</p>
<div class="card-carousel" id="debug_id_1">
  <button class="button-spin counterclockwise">&lt;</button>
  <div class="inner-carousel">
    <div>
      <h4>Now, now. Perfectly symmetrical violence never solved anything.</h4>
      <p>If we can hit that bullseye, the rest of the dominoes will fall like a house of cards.<br>Checkmate.</p>
      <a href="#" onclick="return false;">Blame the wizards!</a>
    </div>
    <div>
      <h4>No! The cat shelter's on to me.</h4>
      <p>I decline the title of Iron Cook and accept the lesser title of Zinc Saucier, which I just made up.<br>Uhh… also, comes with double prize money.</p>
      <a href="#" onclick="return false;">Good news everyone!</a>
    </div>
    <div>
      <h4>Acting Unit 0.8</h4>
      <p>You've killed me!<br>Oh, you've killed me!<br>File not found.</p>
      <a href="#" onclick="return false;">Goodbye, cruel lamp</a>
    </div>
    <div>
      <h4>Uh, is the puppy mechanical in any way?</h4>
      <p>I'm sorry, guys. I never meant to hurt you. Just to destroy everything you ever believed in.</p>
      <a href="#" onclick="return false;">Leela's gonna kill me</a>
    </div>
    <div>
      <h4>Dr. Zoidberg, that doesn't make sense.</h4>
      <p>And remember, don't do anything that affects anything, unless it turns out you were supposed to, in which case, for the love of God, don't not do it</p>
      <a href="#" onclick="return false;">I will destroy you!</a>
    </div>
  </div>
  <button class="button-spin clockwise">&gt;</button>
</div>
<p>Content after... You can't just have your characters announce how they feel. That makes me feel angry! Ah, the 'Breakfast Club' soundtrack! I can't wait til I'm old enough to feel ways about stuff! No! Don't jump! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife holding up? …To shreds, you say.</p>

<div class="card-carousel" id="debug_id_2">
  <button class="button-spin counterclockwise">&lt;</button>
  <div class="inner-carousel">
    <div>
      <h4>2Now, now. Perfectly symmetrical violence never solved anything.</h4>
      <p>2If we can hit that bullseye, the rest of the dominoes will fall like a house of cards.<br>Checkmate.</p>
      <a href="#" onclick="return false;">Blame the wizards!</a>
    </div>
    <div>
      <h4>2No! The cat shelter's on to me.</h4>
      <p>2I decline the title of Iron Cook and accept the lesser title of Zinc Saucier, which I just made up.<br>Uhh… also, comes with double prize money.</p>
      <a href="#" onclick="return false;">Good news everyone!</a>
    </div>
    <div>
      <h4>2Acting Unit 0.8</h4>
      <p>2You've killed me!<br>Oh, you've killed me!<br>File not found.</p>
      <a href="#" onclick="return false;">Goodbye, cruel lamp</a>
    </div>
    <div>
      <h4>2Uh, is the puppy mechanical in any way?</h4>
      <p>2I'm sorry, guys. I never meant to hurt you. Just to destroy everything you ever believed in.</p>
      <a href="#" onclick="return false;">Leela's gonna kill me</a>
    </div>
  </div>
  <button class="button-spin clockwise">&gt;</button>
</div>
<p>Content after... You can't just have your characters announce how they feel. That makes me feel angry! Ah, the 'Breakfast Club' soundtrack! I can't wait til I'm old enough to feel ways about stuff! No! Don't jump! Oh, how awful. Did he at least die painlessly? …To shreds, you say. Well, how is his wife holding up? …To shreds, you say.</p>

Now, style the image carousel using the following CSS styles:

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  background-color: #f0f2f5;
  font-family: "Open Sans";
  font-weight: 300;
  padding: 10px 40px;
}

h4 {
  font-family: "Open Sans";
  font-weight: 300;
}

p {
  font-size: 12px;
}
.cd__main{
display: block !important;
}
.card-carousel {
  position: relative;
  margin: 0 auto 0 auto;
  padding: 0;
  max-width: 220px;
  max-width: 100%;
  height: 450px;
  perspective: 2000px;
  perspective-origin: top;
}
.card-carousel .button-spin {
  position: absolute;
  top: 50%;
  border: 0 none;
  background-color: transparent;
  cursor: pointer;
  font-family: "Open Sans";
  font-weight: 800;
  padding: 10px 16px;
  text-shadow: 1px 1px 4px rgba(0, 54, 90, 0.5);
}
.card-carousel .button-spin:hover {
  box-shadow: 0px 4px 4px 4px rgba(0, 54, 90, 0.15);
}
.card-carousel .button-spin:active {
  box-shadow: none;
}
.card-carousel .button-spin.counterclockwise {
  left: 0;
}
.card-carousel .button-spin.clockwise {
  right: 0;
}
.card-carousel .inner-carousel {
  position: relative;
  width: 225px;
  margin: 0 auto;
  top: 80px;
  transform-style: preserve-3d;
}
.card-carousel .inner-carousel > div {
  position: absolute;
  margin: 0 auto;
  padding: 20px;
  width: 220px;
  height: 300px;
  opacity: 1;
  background-color: #fff;
  color: #000;
  border-radius: 10px;
  transition: all 0.5s ease-out;
  z-index: 1;
  box-shadow: 0px 10px 10px 10px rgba(0, 54, 90, 0.15);
}
.card-carousel .inner-carousel > div:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  opacity: 0.6;
  background-color: #ddd;
  z-index: 1;
}
.card-carousel .inner-carousel > div.counterclockwise:after, .card-carousel .inner-carousel > div.clockwise:after {
  opacity: 0.4;
  cursor: pointer;
}
.card-carousel .inner-carousel > div.front:after {
  content: none;
}
.card-carousel .inner-carousel > div.front {
  background-color: #1C9577;
  background-image: radial-gradient(circle 200px at center right, #2ABA96, #1C9577);
  color: #fff;
}
.card-carousel .inner-carousel > div.front a {
  box-shadow: 0px 5px 5px 5px rgba(0, 54, 90, 0.15);
}
.card-carousel .inner-carousel > div.front a:hover, .card-carousel .inner-carousel > div.front a:focus {
  border: 2px solid #48CFAD;
  padding: 5px 0;
}
.card-carousel .inner-carousel > div.front a:active {
  box-shadow: none;
}
.card-carousel .inner-carousel > div a {
  position: absolute;
  text-align: center;
  bottom: 30px;
  display: block;
  width: 180px;
  border: 1px solid #c9c9c9;
  border-radius: 16px;
  padding: 6px 0;
  font-size: 12px;
  font-weight: 500;
  color: #000;
  text-decoration: none;
  background-color: #fff;
  box-shadow: 0px 5px 8px 3px rgba(0, 54, 90, 0.1);
}

Finally, add the following JavaScript function for its functionality:

/*
* My adaptation of:
*   Flux 3D Carousel
*   Author: Dean Coulter
*   Licensed under the MIT license
*   Version 0.1
*
*   - Changed from figure element cards to any html.
*   - Removed use of id, to allow multiple carousels.
*   - Blocking of events on cards in the background.
*   - Dimming of cards in the background.
*   - Fixed continuous rotation.
*   - Added functionality for multiple carousels.
*   - Adding clickable arrow icon buttons on the sides.
*/
function cardCarousel3d(carousels){
  var rotateHandler = function(evt) {
    var carousel = this.parentElement;
    if(carousel.classList.contains('card-carousel') === false){
      var carousel = carousel.parentElement;
    }
    var rotate_int = parseInt(carousel.dataset.rotateInt || 0);
    if(this.classList.contains('counterclockwise')){
      rotate_int += 1;
    } else if(this.classList.contains('clockwise')){
      rotate_int -= 1;
    }
    carousel.dataset.rotateInt = rotate_int;
    animate_slider(carousel);
  }
  for(var i = 0; i < carousels.length; i++) {
    var carousel = carousels[i];
    var inner = carousel.querySelector('.inner-carousel');
    var cards = carousel.querySelectorAll('.inner-carousel > div');
    var size = cards.length;
    var panelSize = inner.clientWidth;
    var translateZ = Math.round( ( panelSize / 2 ) / Math.tan( Math.PI / size ) ) * 1.7;
    inner.style.transform = "rotateY(0deg) translateZ(-" + translateZ + "px)";
    var btnLeft = carousel.querySelector('.button-spin.counterclockwise');
    if(btnLeft !== null) {
      btnLeft.addEventListener("click", rotateHandler, false);
    }
    var btnRight = carousel.querySelector('.button-spin.clockwise');
    if(btnRight !== null) {
      btnRight.addEventListener("click", rotateHandler, false);  
    }
    animate_slider(carousel);
  }
  
  function animate_slider(carousel){
    var rotate_int = parseInt(carousel.dataset.rotateInt || 0);
    var inner = carousel.querySelector('.inner-carousel');
    var cards = carousel.querySelectorAll('.inner-carousel > div');
    var size = cards.length;
    var panelSize = inner.clientWidth;
    var translateZ = Math.round( ( panelSize / 2 ) / Math.tan( Math.PI / size ) ) * 1.7;
    var rotateY = 0;
    var ry =  360 / size;
    rotateY = ry * rotate_int;

    for(var i = 0; i < size; i++){
      var z = (rotate_int * ry) + (i * ry);
      var child = cards[i];
      child.style.transform = "rotateY(" + z + "deg) translateZ(" + translateZ + "px) rotateY(" + (-z).toString() + "deg)";
      child.classList.remove('clockwise');
      child.classList.remove('front');
      child.classList.remove('counterclockwise');
      child.removeEventListener("click", rotateHandler, false);
      var zz = z % 360;
      if(zz === 0) {
        child.classList.add('front');
      } else if (zz === ry || zz === -360 + ry) {
        child.classList.add('clockwise');
        child.addEventListener("click", rotateHandler, false);
      } else if (zz === 360 - ry || zz === 0 - ry) {
        child.classList.add('counterclockwise');
        child.addEventListener("click", rotateHandler, false);
      }
    }
  }
}

cardCarousel3d(document.querySelectorAll('.card-carousel'));

That’s all! hopefully, you have successfully created our project. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *