Search code examples
jqueryposition

Group elements by position


A #gal container is loaded with lots of images (~60), all with defined CSS height (100px) and margin 5px;

Now, logically, the images widths may vary and when all images are visible, we cannot count the same number of images-per-'line' as they are all floated down if not room available to fit the #gal width:

| ___ __ _____ _ | <--- the #gal with images inside
| __ ______      |
| ______ _ __ __ |
| __ ______      |
| _______ ____ _ |

How to group all images in the 'first' line (second... third...) by wrap()ing them into a DIV ?

So here is a first idea: - after the page is loaded and images are positioned - we could group all the images by its .position().top:

5  5  5  5
120 120
245 245 245 245 
380 380
525 525 525

EXAMPLE

Any idea?


Solution

    • Create a function that returns the ".wrapper" Element using jQuery's Object Element creator.
    • Inside a single loop check for the .next() element position is greater than the current one's.
      If true, pass to the $wrap() function a set of elements in the range of last-known-index to current index + 1 by using .slice().
    • Insert the generated wrappers Elements into and array, and once the work is done append that array to the #gal parent.

    const wrapGalImg = () => {
    
      const $el = $('#gal img'),
        $wrap = ($ch) => $('<div>', {'class':'wrapper', append:$ch}),
        wraps = []; // Array of wrapper elements with children
      let i = 0;
    
      $el.each((ei, ele) => {
        const $next = $(ele).next();
        if($next[0] && $next.position().top == $(ele).position().top) return;
        wraps.push($wrap($el.slice(i, ei+1)));
        i = ei+1;
      });
      
      $('#gal').append( wraps ); // Append all wrappers. Once.
    
    }
    
    $(window).on('load', wrapGalImg);
    *{margin: 0;}
    
    #gal img {
      vertical-align: top;
      height: 60px;
    }
    
    .wrapper {
      background: #f00;
      margin: 1px 0;
    }
    <div id="gal">
      <img src="http://dummyimage.com/180x120/000/fff?text=FIRST">
      <img src="http://dummyimage.com/175x104/f0f/fff">
      <img src="http://dummyimage.com/150x100/a3d/fff">
      <img src="http://dummyimage.com/278x125/cf5/fff">
      <img src="http://dummyimage.com/199x120/e46/fff">
      <img src="http://dummyimage.com/207x480/361/fff">
      <img src="http://dummyimage.com/400x107/081/fff">
      <img src="http://dummyimage.com/50x40/cc3/fff">
      <img src="http://dummyimage.com/700x500/233/fff">
      <img src="http://dummyimage.com/300x120/a26/fff">
      <img src="http://dummyimage.com/301x177/f1d/fff">
      <img src="http://dummyimage.com/164x239/d34/fff">
      <img src="http://dummyimage.com/200x300/34e/fff">
      <img src="http://dummyimage.com/175x120/72a/fff">
      <img src="http://dummyimage.com/210x110/112/fff">
      <img src="http://dummyimage.com/278x225/644/fff">
      <img src="http://dummyimage.com/300x120/dc3/fff">
      <img src="http://dummyimage.com/90x104/b30/fff">
      <img src="http://dummyimage.com/120x60/bb3/fff">
      <img src="http://dummyimage.com/140x125/aa3/fff?text=LAST">
    </div>
    
    <script src="https://code.jquery.com/jquery-3.3.1.js"></script>


    So, no need for multiple loops, cloning or removing elements.