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.
Ultimately I want to slide them together so that it's as compact as possible like this:
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
To center both vertically and horizontally, use padding and text-align: center : I am vertically and horizontally centered.
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.
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.
<!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/
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();
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