I am working on an event system which is basically a container with 720px height with each pixel representing one minute from 9AM to 9PM and has width of 620px (10px padding from left and right)
The natural requirement for the calendar system is that:
- The objects should be laid out so that they do not visually overlap.
- If there is one event in a time slot, its width will be 600px
- Every colliding event must be the same width as every other event that it collides width.
- An event should use the maximum width possible while still adhering to the first constraint.

The input will be an array something like:
[
{id : 1, start : 30, end : 150}, // an event from 9:30am to 11:30am
{id : 2, start : 540, end : 600}, // an event from 6pm to 7pm
{id : 3, start : 560, end : 620}, // an event from 6:20pm to 7:20pm
{id : 4, start : 610, end : 670} // an event from 7:10pm to 8:10pm
]
I have created the needed layout but I am stuck with JavaScript part 🙁 This is what I have so far:
var Calendar = function() {
var layOutDay = function(events) {
var eventsLength = events.length;
if (! eventsLength) return false;
// sort events
events.sort(function(a, b){return a.start - b.start;});
for (var i = 0; i < eventsLength; i++) {
// not sure what is next
}
};
return {
layOutDay : layOutDay,
}
}();
Need to create divs and position them as per above requirements.
Any help will be greatly appreciated.
Here is a working solution: http://jsbin.com/igujil/13/edit#preview
As you can see, it’s not an easy problem to solve. Let me walk you through how I did it.
The first step, labelled Step 0, is to make sure the events are sorted by id. This will make our lives easier when we start playing with the data.
Step 1 is to initialize a 2-dimensional array of timeslots. For each minute in the calendar, we’re going to make an array which will contain the events that take place during that minute. We do that in…
Step 2! You’ll note I added a check to make sure the event starts before it ends. A little defensive, but my algorithm would hit an infinite loop on bad data, so I want to make sure the events make sense.
At the end of this loop, our timeslot array will look like this:
0: []
1: []
…
30: [1]
31: [1]
…
(skipping ahead to some interesting numbers)
540: [2]
560: [2,3]
610: [3,4]
I encourage you to add
console.log(timeslots)just before Step 3 if you’re confused/curious. This is a very important piece of the solution, and the next step is a lot more difficult to explain.Step 3 is where we resolve scheduling conflicts. Each event needs to know two things:
(1) is easy because of how our data is stored; the width of each timeslot’s array is the number of events. Timeslot 30, for example, has only 1 event, because Event #1 is the only one at that time. At Timeslot 560, however, we have two events, so each event (#2 and #3) gets a count of two. (And if there was a row with three events, they would all get a count of three, etc.)
(2) is a little more subtle. Event #1 is obvious enough, because it can span the entire width of the calendar. Event #2 will have to shrink its width, but it can still start along the left edge. Event #3 can’t.
We solve this with a per-timeslot variable I called
next_hindex. It starts at 0, because by default we want to position along the left edge, but it will increase each time we find a conflict. That way, the next event (the next piece of our conflict) will start at the next horizontal position.Step 4 is quite a bit more straightforward. The width calculation uses our max-conflict count from Step 3. If we know we have 2 events at 5:50, for example, we know each event has to be 1/2 the width of the calendar. (If we had 3 events, each would be 1/3, etc.) The x-position is calculated similarly; we’re multiplying by the hindex because we want to offset by the width of (number of conflict) events.
Finally, we just create a little DOM, position our event divs, and set a random colour so they’re easy to tell apart. The result is (I think) what you were looking for.
If you have any questions, I’d be happy to answer. I know this is probably more code (and more complexity) than you were expecting, but it was a surprisingly complicated problem to solve 🙂