Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rearrange chain based on window width

Solved: I've got the @EdnilsonMaia answer and adapted it http://codepen.io/anon/pen/QNGroX

I have a layout where there are a chain of users like so:

Window
-------------------
O - O - O - O - O |
                | |
O - O - O - O - O |
|                 |
O - O - O         | 
------------------
O = user
- = chain (icon)

chain layout

When the user resizes the the window the number of users per line decrease and the chain need to be rearranged increasing the number of lines and decreasing the number of users per line. I found it very similar to the sorting algorithms.

Note that when rearranged the last user of the first line go to the last position of the second line and the first user of the second line to the first position of the third line, it must respect the order they are connected while changing positions.

What I need is a direction on how to code the algorithm in JS. So far my code changes the position of the users but doesn't take into consideration the correct order and also the chain icons. It also doesn't work when resizing back to the original size.

This is my code, note that each line is a separated UL:

function log(msg, debug) {
  debug = typeof debug !== 'undefined' ? debug : true;
  if (debug) {
    console.log(msg);
  }
}
$(document).ready(function() {
  $(window).on('resize', function() {
    rearrangeChain(true);
  });

  function rearrangeChain(debug) {
    debug = typeof debug !== 'undefined' ? debug : false;

    log('------------------------', debug);

    var win = $(window);

    // Percentage
    // 1170 -------- 100%
    // size -------- x
    var totalWindowWidth = 1170;
    var windowWidth = win.width();
    var percentage = (windowWidth * 100) / totalWindowWidth;
    log('Window:' + percentage + '%', debug);
    log('Window width:' + win.width() + 'px', debug);

    var slotSize = 146.25;
    var imagesPerLine = Math.floor(windowWidth / slotSize);

    log('Images per line: ' + imagesPerLine, debug);

    $('ul.users-chain-home').each(function(k) {
      //var element = $(this);

      var usersNumber = 1;
      $(this).find('.user-image').each(function() {
        var element = $(this).parent();
        //console.log('users number', usersNumber, '>', imagesPerLine);
        if (usersNumber > imagesPerLine) {
          var nextLine = $('ul.users-chain-home')[k + 1];
          console.log('Next line ' + (k + 1), nextLine);
          if (typeof nextLine != 'undefined') {
            console.log('Next line append', element[0]);
            nextLine.appendChild(element[0]);
          }
        }
        usersNumber++;

      });
      log('Users per line chain ' + k + ': ' + usersNumber, debug);
    });



  }

  rearrangeChain(true);
});
div#wrapper {
  display: inline-block
}
ul.users-chain-home {
  list-style-type: none;
  margin: 0;
  padding: 0
}
ul.users-chain-home li {
  display: inline;
}
ul.users-chain-home li div.chain-icon {
  vertical-align: middle;
  display: table-cell;
  width: 40px;
  height: 96px;
  text-align: center;
}
ul.users-chain-home li div.join-chain {
  vertical-align: middle;
  display: table-cell;
  height: 96px;
  text-align: center;
}
img.chain-icon-vertical {
  margin: 5px 42px 5px 0;
}
img.chain-icon-vertical-left {
  margin: 5px 0 5px 38px;
}
<div id="wrapper">
  <div>
    <ul class="users-chain-home">
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon show-for-large">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li class="show-for-large">
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon show-for-large">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li class="show-for-large">
        <img src="img/users/2.jpg" class="user-image">
      </li>

    </ul>
  </div>

  <div class="text-right">
    <img src="img/assets/chain-icon-vertical.gif" class="chain-icon-vertical">
  </div>

  <div class="text-right">
    <ul class="users-chain-home">
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
    </ul>

  </div>

  <div>
    <img src="img/assets/chain-icon-vertical.gif" class="chain-icon-vertical-left">
  </div>

  <div>
    <ul class="users-chain-home">
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/1.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/2.jpg" class="user-image">
      </li>
      <li class="chain-icon">
        <div class="chain-icon">
          <img src="img/assets/chain-icon.gif">
        </div>
      </li>
      <li>
        <img src="img/users/3.jpg" class="user-image">
      </li>

    </ul>

  </div>

</div>
like image 444
Keyne Viana Avatar asked Mar 13 '16 14:03

Keyne Viana


2 Answers

Try my solution:

1) PHP/HTML

Generate html elements.

<div id="content">

<ul class="user-chain">
<?php for($i = 1; $i<=50; $i++): ?>
    <li class="user-item">
        <div class="user-container">
            <img src="https://cdn1.iconfinder.com/data/icons/user-pictures/100/male3-128.png" class="user-avatar">
        </div>
    </li>
<?php endfor; ?>
</ul>

</div>

2) CSS

Note: I use FontAwesome to generate the icon

    .user-chain { margin: 0; padding: 0 }
    .user-item { margin: 15px; list-style: none; max-width: 100px; position: absolute; }
    .user-container { position: relative }
    .user-avatar { max-width: 100px; max-height: 100px; display: block }

    .user-container.chain:before {
        content: "\f0c1";
        font-family: FontAwesome;
        font-style: normal;
        font-weight: normal;
        text-decoration: inherit;
        /*--adjust as necessary--*/
        color: #000;
        font-size: 18px;
        padding-right: 0.5em;
        position: absolute;
    }

    .user-container.chain-ltr:before {
         top: 50%;
         left: -24px;
         -ms-transform: rotate(-45deg); /* IE 9 */
         -webkit-transform: rotate(-45deg); /* Chrome, Safari, Opera */
         transform: rotate(-45deg);
         margin-top: -10px;
     }
    .user-container.chain-rtl:before {
         top: 50%;
         right: -32px;
         -ms-transform: rotate(-45deg); /* IE 9 */
         -webkit-transform: rotate(-45deg); /* Chrome, Safari, Opera */
         transform: rotate(-45deg);
         margin-top: -10px;
     }
    .user-container.chain-ttd:before {
          top: -20px;
        right: 50%;
        -ms-transform: rotate(45deg); /* IE 9 */
        -webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */
        transform: rotate(45deg);
        margin-right: -12px;
    }

3) jQuery

Get the container width of the list and calculate the maximum items per line. Define a flag to inform the direction of the next item in the chain. Use the variable (i) to calculate margins for every item and the direction of the next item. Calculate the amount of lines to define top margin.

$(document).ready(function() {

var w_container = $('#content').width();
var elm_h = 100;
var elm_w = 100;
var elm_m = 15;
var maxNodesInLine = Math.floor(w_container / (elm_w + (elm_m *2)));
var direction = 'ltr';
var line = 0;
var i = 0;

function ltr(elm){
    console.log('function ltr');
    direction = 'ltr';

    if(i == 0){
        elm.css({"margin-left":0});
    } else{
        elm.css({"margin-left":(elm_w+(elm_m*2))*i});
    }
    elm.css({"margin-top":(elm_h+(elm_m*2))*line});

    i++;
}
function rtl(elm){
    console.log('function rtl');

    if(i == (maxNodesInLine)){
        elm.css({"margin-left":elm_m*2});
    } else{
        elm.css({"margin-left":(elm_w+(elm_m*2))*(maxNodesInLine - (i+1))});
    }
    elm.css({"margin-top":(elm_h+(elm_m*2))*line});

    i++;
}
function ttd(elm){
    console.log('function ttd');

    elm.css({"margin-top":(elm_h+(elm_m*2))*line});

    if(direction == 'ltr'){
        direction = 'rtl';
        elm.css({"margin-left":(elm_w+(elm_m*2))*(i-1)});
    }
    else{
        direction = 'ltr';
        elm.css({"margin-left":0});
    }

    i=1;
}

$( ".user-item" ).each(function( index ) {

    elm = $(this);

    if(direction == 'ltr' && i < maxNodesInLine)
    {
        ltr(elm);
        $(elm).not(':first-child').children('.user-container').addClass('chain chain-ltr');
    }
    else if(i == (maxNodesInLine)){
        line++;
        ttd(elm);
        $(elm).children('.user-container').addClass('chain chain-ttd');
    }
    else {
        rtl(elm);
        $(elm).children('.user-container').addClass('chain chain-rtl');
    }

});

$(window).on('resize', function() {
    console.log('Window re-sized.');
    // todo: funtcion to update when resize window...
});

});

4) Demo https://jsfiddle.net/jftqLf1d/1/

like image 167
Emaia Avatar answered Sep 30 '22 07:09

Emaia


Well, you can try the following. First make your users absolutely positioned:

div {
  background: lightgreen;
  line-height: 30px;
  position: absolute;
  text-align: center;
  width: 30px;
}

Then use the following approach: instead of sorting the HTML elements would be way easier to just calculate a location of an element based on simple maths. See:

// generate 100 divs
document.body.innerHTML = Array.apply(null, new Array(100)).map(function(e, index) {
    return '<div>' + index + '</div>';
}).join('');

// function which recalculates the positions
function render() {
  var lineLength, margin = 10, height = 30, width = 30;

  lineLength = Math.floor(document.body.clientWidth / (margin + width));

    Array.apply(null, document.querySelectorAll('div')).forEach(function(element, index) {
    var line = Math.floor(index / lineLength),
        indexInLine = index - line * lineLength;

    if (line % 2) indexInLine = lineLength - 1 - indexInLine;

    element.style.left = indexInLine * (width + margin) + 'px';
    element.style.top = line * (height + margin) + 'px';
  });
}

// initial rendering call
render();

// call rendering every time window is resized
window.onresize = function() {
  render();
};

See jsfiddle. This is absolutely not a final solution, but a direction to go. You can improve many things starting from getting width / height / margin from CSS automatically; getting the parent instead of body for calculations; etc.

Adding a chain icon should be very easy: just make it as an ::after pseudo-element in CSS instead of HTML (by that you avoid lots of repetitions) and for every element in the end of the line just rotate it down (by assigning a proper class).

like image 33
smnbbrv Avatar answered Sep 30 '22 07:09

smnbbrv