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)
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>
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/
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With