Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertically align div's but keeping horizontal position intact

Tags:

From a database I'm pulling a kind of timeline of Div's with a certain starting point and certain end point. Some of them overlap, some of them can be fitted next to each other. from Database

Ultimately I want to slide them together so that it's as compact as possible like this: what we want to accomplish

I'm doubting how to approach this challenge: through a server side (php) script or with some javascript floating script thingy. Or off course a completely different approach

Could some one push me in the right direction?

Edit:: It's important, as it's a timeline, that the horizontal position of the div's remain the same. So floating all the divs to the left or inline-block them is no option :)

My database setup:

id | name | start | end   1  | a    | 2     | 7   2  | b    | 5     | 10   etc 
like image 958
stUrb Avatar asked Dec 04 '12 02:12

stUrb


People also ask

How do you vertically align elements in CSS?

To center both vertically and horizontally, use padding and text-align: center : I am vertically and horizontally centered.

How do you place a div in the center of the page?

First position the div's top left corner at the center of the page (using position: fixed; top: 50%; left: 50% ). Then, translate moves it up by 50% of the div's height to center it vertically on the page. Finally, translate also moves the div to the right by 50% of it's width to center it horizontally.

How do I vertically align two divs?

To align two <div> elements vertically in Bootstrap 3, you can try using the CSS Flexible Box Layout. In the example below, we display the needed row as a flex container box with the CSS display property and then, align the flex-items (columns) vertically with the align-items property.


2 Answers

<!DOCTYPE html> <html> <!--   Created using jsbin.com   Source can be edited via http://jsbin.com/udofoq/26/edit --> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <meta charset=utf-8 /> <title>JS Bin</title> <style id="jsbin-css">div.blue {     background-color: #a4dcdf; }  div.orange {     background-color: #fd9226; }  div.green {     background-color: #88b37e; }  div.yellow {     background-color: #d8d03f; }  div.red {     background-color: #c16558; } div.grey {     background-color: #cdcdcd; } div.hours1{   top: 0px;   left: 10px;   width: 100px;//(110-10) } div.hours2{   top: 30px;   left: 80px;   width: 50px; } div.hours3{   top: 60px;   left: 120px;   width: 50px; }  div.hours4{   top: 90px;   left: 5px;   width: 70px; }  div.hours5{   top: 120px;   left: 110px;   width: 30px; } div.hours6{   top: 150px;   left: 130px;   width: 70px; } div.hours {   position: absolute;   height:20px;   color: white;   text-align:center;   border:white;   -webkit-box-shadow: 3px 3px 6px 2px rgba(00, 00, 00, .2);   box-shadow: 3px 3px 6px 2px rgba(00, 00, 00, .2);   font: bold 18px Arial, Helvetica, Geneva, sans-serif;   line-height:20px;      }  button{     position:static;     margin-top:200px; } .collapse, .overlap1, .overlap2, .overlap3, reset{     float:left; } </style></head> <body>   <div class="hours hours1 orange">A</div> <div class="hours hours2 yellow">B</div> <div class="hours hours3 blue">C</div> <div class="hours hours4 green">D</div> <div class="hours hours5 red">E</div> <div class="hours hours6 grey">F</div> <button class="collapse">collapse</button> <button class="overlap1">sort</button> <button class="reset">reset</button>  <script> data1 = [   [1, 10, 110],   [2, 80, 130],   [3, 120, 170],   [4, 5, 70],   [5, 110, 140],   [6, 130, 180] ];  //just added for console output not needed var divider=""; for (var i = 0; i < 80; i++) {   divider += "_"; }  console.log(divider); console.log("ORIGINAL ARRAY DATA1:", data1);   //add a column to keep track of the row, to start set it to  row 1 data1 = $.each(data1, function(index, value) {   value[3] = 0; });  console.log(divider); console.log("ORIGINAL dataA WITH ADDED COLUMN:", data1);  function timelinesort(dataA){  //make a new Array to store the elements in with their new row number var dataB = dataA.slice(0, 1);  console.log(divider); console.log("INITIALIZED dataB WITH FIRST ELEMENT FROM dataA:", dataB);   //initialize the counter var counter = 0;  console.log(divider); console.log("INITIALIZED ROUNDS COUNTER:", counter);   dataA = $.map(dataA, function(value1, index1) {  //increment counter with 1  counter++;  console.log(divider); console.log("INCREMENTED ROUNDS COUNTER:", counter);     dataA = $.map(dataA, function(value2, index2) {       //exclude comparing an element with itself     if(value2 != dataB[0]) {       //check to see if elements overlap       if(value2[2] >= dataB[0][1] && value2[1] <= dataB[0][2]) {         console.log(divider);         console.log("Round " + counter  + " from dataA: [" + value2 + "] overlaps with " + dataB[0] + " incrementing row counter with 1");         //increment the value in column 3 (row counter) of the array         value2[3]++;         console.log(divider);         console.log("Now the dataA has changed to this:", dataA);         console.log("Meanwhile data1 has changed to this:", data1);       } else {         //if no overlap occurs check if the element is not already in the dataB array and if not check if it doesn't overlap with the existing elements         if($.inArray(value2, dataB) == -1) {           $.each(dataB, function(index3, value3) {             if(value3[2] >= value2[1] && value3[1] <= value2[2]) {               console.log(divider);               console.log("Round " + counter + " from dataA: [" + value2 + "] overlaps with " + value3 + " incrementing row counter with 1");               dataB.pop();               //increment the value in column 3 (row counter) of the array               value2[3]++;             } else {               //if no overlap occurs add the value to dataB               dataB.push(value2);               console.log(divider);               console.log("Added [" + value2 + "] to dataB and now dataB has changed to this: ", dataB);             }           });         } else {           dataB.push(value2);           console.log("Added [" + value2 + "] to dataB and now dataB has changed to this: ", dataB);         }       }     }     return [value2];   });   dataA = jQuery.grep(dataA, function(item) {     return jQuery.inArray(item, dataB) < 0;   });   if(dataA.length >= 1) {     dataB.unshift(dataA[0]);     dataB = dataB.splice(0, 1);   } else {     dataA = [];   }  });  } //run the function timelinesort(data1);  console.log(divider); console.log("Finally the data1 has changed to this:", data1);   $(".collapse").click(function() {   $.each(data1, function(index, value) {     $("div.hours" + (index + 1)).animate({       "top": 0     }, "slow");   });  });  $(".overlap1").click(function() {   $.each(data1, function(index, value) {     console.log("div.hours" + (index + 1) + ":" + (value[3]) * 26);     $("div.hours" + (index + 1)).animate({       "top": (value[3]) * 26     }, "slow");   });  });  $(".reset").click(function() {   $.each(data1, function(index, value) {     $("div.hours" + (index + 1)).removeAttr('style');   });  }); </script> </body> </html> 

What I did was collapse all rows onto the first row, then check which ones overlapped with the originals of that row and if so increment the row number over the overlapping ones, then go to the next row and repeat the process until all elements are neatly stacked.

You still have to clean up the javascript/jquery stuff and put it in a nice function or so. But as proof of concept it seems to work

working example:


http://jsbin.com/udofoq/26/watch

or

http://jsfiddle.net/stofke/7VP5U/

like image 107
Stofke Avatar answered Feb 02 '23 00:02

Stofke


Check out my fiddle here. I think it does what you need with unlimeted number of blocks. Blocks data is taken from HTML-table.

JS:

var data = [],     rows = [],     chart = $('.wrapper-inner');   function DataItem(id, name, start, end){      this.id = id;      this.name = name;      this.start = start;      this.end = end; }  $('.data tr').each(function() {     var $this = $(this),         item = new DataItem( $this.find('td:eq(0)').text(),                              $this.find('td:eq(1)').text(),                              $this.find('td:eq(2)').text(),                              $this.find('td:eq(3)').text() );         data.push(item); });  function addRow(){     var row = {         el : $('<div class="row"></div>').appendTo(chart),         positions: []     };      rows.push( row ); }  function checkRow(rowId, item){             var isRowAvailible = true;      for (var i = 0; i < +item.end - +item.start; i++){         if (rows[rowId].positions[+item.start + i]){             isRowAvailible = false;             break;         }     }      return isRowAvailible; }  function markRowPositions(rowId, item){       for (var i = 0; i < item.end - item.start; i++){         rows[rowId].positions[+item.start + i] = true;     }  }  function addItems(){     for (var i = 0; i < data.length; i++){         (function(i){             setTimeout(function() {addItem(data[i])}, 100 * i);         })(i)     } }  function addItem(item){     var rowToAdd = false,         itemEl = $('<div class="item"></div>');      for (var i = 0; i < rows.length; i++){         if ( checkRow(i, item) ){             rowToAdd = i;             break;             }     }      if (rowToAdd === false){         addRow();         rowToAdd = rows.length - 1;     }      rows[ rowToAdd ].el.append(itemEl);          console.log(itemEl.css('opacity'))      itemEl.css({         'left': item.start * 30,         'opacity' : 1,         'width': ( ( item.end - item.start ) * 30 ) - 2     });       markRowPositions(rowToAdd, item);    }  addItems(); 
like image 23
Michael Malinovskij Avatar answered Feb 01 '23 23:02

Michael Malinovskij