Search code examples
javascripthtmldomcarousel

Using JavaScript to determine the middle div, within a div


I've created a basic multi-item horizontal carouse, which moves through a div of images, when you click either a "left" or "right" button.

I want to write some JavaScript logic, which tells me which div, is the most centered div on screen, within the container DOM node:\

<section class="items-container"></section>

document.addEventListener('DOMContentLoaded', function() {
  console.log('app.js loaded');

  const pixabayAPIService = PixabayAPIService();
  const carouselContainer = document.getElementById('carousel-container');
  const previousButton    = document.getElementById('previous');
  const nextButton        = document.getElementById('next');
  let count               = 0;

  console.log('count', count);

  pixabayAPIService.getImages();

  slideImages = (direction) => {
    const totalChildren = carouselContainer.getElementsByTagName('div').length;
    console.log('totalChildren', totalChildren);

    direction === 'left' ? count ++ : count --;
    console.log('updated count', count);

    carouselContainer.classList.add('horizTranslate');
    carouselContainer.style.left = count * 200 + 'px';
    carouselContainer.classList.add("slideOutLeft")

    previousButton.style.display = count < 0 ? 'block' : 'none';
    nextButton.style.display = count > 5 - totalChildren ? 'block' : 'none';
  }

  previousButton.addEventListener('click', event => {
    event.preventDefault();
    slideImages('left');
  });

  nextButton.addEventListener('click', event => {
    event.preventDefault();
    slideImages('right');
  });

  if (count === -1) {

  }
});
.home-product-new-hldr {
    position: relative;
    /* width:1140px; */
    border: 0px solid black;
    width: 1000px;
}

.carousel-container {
    width: 1000px;
    overflow:hidden;
    border: 1px solid red;
  }

.items-container {
    border: 3px solid green;
    width: 1000px;
    height: 200px;
    margin: 0 auto;
    display: flex;
    position:relative;
    white-space:nowrap;
}

.item {
    border: 0px solid green;
    width: 200px;
    margin: 0 auto;
    display: inline-block;
    vertical-align: top;
    justify-content: space-between;
}

.horizTranslate {
    -webkit-transition: 1s;
    -moz-transition: 1s;
    -ms-transition: 1s;
    -o-transition: 1s;
    transition: 1s;
}
  <body>

    <main>
      <h1>Carousel</h1>

      <section>
          <button id="previous" style="display: none;">left</button>
        </section>

      <div class="frame">
      <div class="carousel-container">
      <section class="items-container" id="carousel-container" style="left: 0px; border: 1px solid red";>
          <div class="item"><img src="https://www.fillmurray.com/g/200/200" /></div>
          <div class="item"><img src="https://www.fillmurray.com/200/200" /></div>
          <div class="item"><img src="https://www.fillmurray.com/200/200" /></div>
          <div class="item"><img src="https://www.fillmurray.com/g/200/200" /></div>
          <div class="item"><img src="https://www.fillmurray.com/200/100" /></div>
          <div class="item"><img src="https://www.fillmurray.com/200/100" /></div>
      </section>
    </div>
  </div>

  <section>
      <button id="next" style="display: block;">right</button>
    </section>

  </main>

  </body>

Yes, there are 6 divs listed there, but when I make my carousel responsive, the number of carousel items within the div will reduce.

So I wanted to know the best way, to calculate the most centered div, within the section node, regardless of screen/device.

Thank you.


Solution

  • Using vanilla JavaScript, we can loop through each of the child DIVs and find which is the most centered by comparing it's left and right edges with the center of the carousel. Here's a CodePen example of the below code in action:

    function getMostCentered(container, items) {
      // Find center of the container
      let container_bounds = container.getBoundingClientRect(),
          center = container_bounds.left + (container_bounds.width / 2);
    
      // Loop through each item and compare with the center
      for (let i = 0; i < items.length; i++) {
        let item = items[i],
            next = items[i+1],
            item_bounds = item.getBoundingClientRect(),
            next_bounds = next && next.getBoundingClientRect();
    
        // Find the first item whose left edge is past the center 
        if (next && next_bounds.left > center) {
          // and compare it with the previous item to see which is closer
          if (next_bounds.left - center < center - item_bounds.right) {
            return next;
          } else {
            return item;
          }
        // If we've hit the last item then it must be closest
        } else if (!next) {
          return item
        }
      }
    }