0

I'm trying to create a tile-like content carousel for a website I'm creating. Basically I need the ordinary content carousel functionality that comes in a lot of different jQuery plug-ins etc. - but instead of the slider being linear, I need the items to shift tiles in a circular manner like this:

Step 1:
enter image description here

Step 2:
enter image description here

Step 3:
enter image description here

I tried creating the setup using Flexbox and some simple jQuery:

$(document).ready(function () {
  
  $(".item").each(function (index) {
    $(this).css("order", index);
  });

  $(".prev").on("click", function () {
    // Move all items one order back

    $(".item").each(function (index) {
      var currentOrder = parseInt($(this).css("order"));
      if (currentOrder == undefined) {
        currentOrder = index;
      }
      var newOrder = currentOrder - 1;
      if (newOrder < 0) {
        newOrder = 5;
      }
      $(this).css("order", newOrder);
    });
  });

  $(".next").on("click", function () {
    // Move all items one order forward

    $(".item").each(function (index) {
      var currentOrder = parseInt($(this).css("order"));
      var newOrder = currentOrder + 1;

      if (newOrder > 5) {
        newOrder = 0;
      }
      $(this).css("order", newOrder);
    });
  });
});
.container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  width: 500px;
}

.item {
  width: 125px;
  height: 75px;
  color: white;
  text-align: center;
  font-size: 24px;
  border: 1px solid white;
  padding-top: 50px;
  box-sizing: content-box;
  background-color: rgb(42, 128, 185);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

        <button class="prev">Prev</button>&nbsp;
        <button class="next">Next</button>&nbsp;

        <div class="container">
            <div class="item one">1</div>
            <div class="item two">2</div>
            <div class="item three">3</div>
            <div class="item four">4</div>
            <div class="item five">5</div>
            <div class="item six">6</div>
        </div>

but this leaves me with some unresolved issues:

  1. How do I animate the tiles when changing the order (when clicking next/prev)?
  2. How do I fix the order so that the items move in a continuous line instead of wrapping to the start of next line (I'd like the order to be like displayed in step 2 -> 3)?

Any existing plug-in (I've looked but can't find any) or codepen etc. would be very much appreciated as I'm not sure if my approach is maintainable (or even doable).

Thanks a bunch :)

isherwood
  • 58,414
  • 16
  • 114
  • 157
InversionDK
  • 125
  • 7
  • Please see [ask] and revise your post title to ask a single clear, specific question. If you find that difficult it may be because your current question is too broad. It seems like you've asked multiple quite different questions here. Also, off-site resource requests (such as plugins) are off topic on SO. – isherwood Aug 29 '22 at 20:40
  • 1
    See [Use transition on flexbox order](https://stackoverflow.com/q/18846481/1264804) and [How can I reverse flexbox direction on wrap?](https://stackoverflow.com/q/59481712/1264804). – isherwood Aug 29 '22 at 20:48

2 Answers2

1

I've used absolute position formula from index to (top, left). Then i've used jQuery to animate that. That's lame but can be improved if that's an issue. It looks nice.

const containerBox = document.querySelector('#container')
let divs = [...containerBox.querySelectorAll('div')]
var size = 100
var margin = 2

function get_top_left(pos) {
  if (pos < divs.length / 2) {
    return {
      left: pos * size + margin * (pos),
      top: 0
    }
  } else {
    return {
      left: (divs.length - pos - 1) * size + margin * (divs.length - pos - 1),
      top: size + margin
    }
  }
}

var offset = 0

function draw() {

  divs.forEach(function(div, index) {
    var len = divs.length
    index = ((index + offset) % len + len) % len
    var pos = get_top_left(index);
    //div.style.left = pos.left + "px"
    //div.style.top = pos.top + "px"
    $(div).animate({
      "left": pos.left + "px",
      "top": pos.top + "px"
    })
  })

}

next.onclick = _ => {
  offset += 1
  draw()
}
prev.onclick = _ => {
  offset -= 1
  draw()
}

draw();
#container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  width: 500px;
  height: 260px;
  margin: 10px;
  position: relative;
}

#container>div {
  width: 100px;
  height: 66px;
  color: white;
  text-align: center;
  font-size: 24px;
  border: 1px solid white;
  padding-top: 34px;
  box-sizing: content-box;
  background: #2a80b9;
  position: absolute;
  top: 0;
  left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="prev">Prev</button>
<button id="next">Next</button>

<div id="container">
  <div> 1 </div>
  <div> 2 </div>
  <div> 3 </div>
  <div> 4 </div>
  <div> 5 </div>
  <div> 6 </div>
</div>
IT goldman
  • 14,885
  • 2
  • 14
  • 28
  • Not too bad :) It's a bit tightly coupled to absolute width etc. but I think I might be able to work it into a grid arrangement or something. For now I've got something to work with. Thanks a lot! :) – InversionDK Aug 30 '22 at 19:12
  • Maybe can prepare (somehow) the css classes beforehand using your css preprocessor (sass or less). Alternatively, see some 3D examples in this [codepen](https://codepen.io/SitePoint/pen/gRJWqm) – IT goldman Aug 30 '22 at 19:45
0

This kind of carousel ?

const
  containerBox   = document.querySelector('#container')
, nextOrder = [3,0,1,4,5,2]
, prevOrder = [1,2,5,0,3,4]
  ;
next.onclick =_=>
  {
  let divs = [...containerBox.querySelectorAll('div')]
  nextOrder.forEach(n=> containerBox.appendChild( divs[n]) )
  }
prev.onclick =_=>
  {
  let divs = [...containerBox.querySelectorAll('div')]
  prevOrder.forEach(n=> containerBox.appendChild( divs[n]) )
  }
#container {
  display        : flex;
  flex-direction : row;
  flex-wrap      : wrap;
  width          : 500px;
  margin : 20px;
  }
#container > div {
  width       : 125px;
  height      : 75px;
  color       : white;
  text-align  : center;
  font-size   : 24px;
  border      : 1px solid white;
  padding-top : 50px;
  box-sizing  : content-box;
  background  : #2a80b9;
}
<button id="prev">Prev</button> 
<button id="next">Next</button> 

<div id="container">
    <div> 1 </div>
    <div> 2 </div>
    <div> 3 </div>
    <div> 6 </div>
    <div> 5 </div>
    <div> 4 </div>
</div>
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40