Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to position divs in horizontal timeline taking into account free space / overlaps

I'm trying to create a horizontal timeline but I'm not sure the best way to go about arranging the events divs correctly. At the moment it looks like this:

<div id="events">
    <div class="event" style="left:25; position:relative;" id="1">• Entry 1</div>
    <div class="event" style="left:25; position:relative;" id="2">• Entry 2</div>
    <div class="event" style="left:50; position:relative;" id="3">• Entry 3</div>
    <div class="event" style="left:375; position:relative;" id="4">• Entry 4</div>
</div>

enter image description here

I'm trying to make Entry 4 position itself at the top (as there are no divs in the way) but I'm not sure the best solution. It also needs to allow for any number of events overlapping.

enter image description here

Most css options / jQuery plugins don't seem to offer a solution as far as I'm aware they are mostly for flexible grids but this only needs to be flexible vertically and have fixed positions horizontally to line up correctly with the dates.

An obvious first step is to position: absolute and set a top: x but how would one go about checking previous entries to make sure it's not overlapping an older & longer entry. The timeline will hold quite a number of events with various lengths so it can't be too intensive either.

Any suggestions for the best/easiest way to do this?

like image 249
Steve Avatar asked Mar 18 '18 16:03

Steve


1 Answers

I suppose you have an events array with start and end dates, then you should check whether events are overlapping by start and end dates. To simulate this, you can check this method:

var events = [{
  start: "2018/10/24 15:00",
  end: "2018/10/24 18:00"
}, {
  start: "2018/10/25 12:00",
  end: "2018/10/26 12:00"
}, {
  start: "2018/10/25 07:00",
  end: "2018/10/25 10:00"
}, {
  start: "2018/10/24 12:00",
  end: "2018/10/24 20:00"
}, {
  start: "2018/10/25 08:00",
  end: "2018/10/25 13:00"
}];

var stack = [],  
  s = 0,
  lastStartDate, lastEndDate, newEvents;
events.sort(function(a,b){
   if(a.start > b.start) return 1;
   if(a.start < b.start) return -1;
   return 0;
});
while (events.length > 0) {
  stack[s] = [];
  newEvents = [];
  stack[s].push(events[0]);
  lastStartDate = events[0].start;
  lastEndDate = events[0].end;
  for (var i = 1; i < events.length; i++) {
    if (events[i].end < lastStartDate) {
      stack[s].push(events[i]);
      lastStartDate = events[i].start;
      delete events[i];
    } else if (events[i].start > lastEndDate) {
      stack[s].push(events[i]);
      lastEndDate = events[i].end;      
    }else{
      newEvents.push(events[i]);
    }
  }
  events = newEvents;
  s++;
}

console.log(stack);

This method picks the first event as the key and checks for other events whether they overlap or not, if they don't overlap, they will be added to the first stack, then if there are any events left, a new stack will be created and then with the remaining events, the code will be run again and a new stack will be prepared again. Until there are any events left in the array, it should continue creating stacks.

Then you can use these stacks to build your events grid. One stack per line.

I used this algorithm in my Evendar plugin. You can check it's grid view.

like image 100
Taha Paksu Avatar answered Sep 27 '22 19:09

Taha Paksu