Visualization of calendar events. Algorithm to layout events with maximum width
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The classic day-view calendar problem is not just "draw overlapping events side by side." The real goal is to assign each event the maximum width it can occupy without covering another event that overlaps in time.
That turns the layout into an interval-graph problem. You group overlapping events together, assign them to columns, and then expand each event horizontally as far as later columns allow.
Model Events As Time Intervals
Each event is an interval with a start and end. Two events conflict if their intervals overlap in time. In a vertical day view:
- vertical position comes from time
- horizontal columns are used only to separate overlapping intervals
A simple event model in Python:
Using minutes keeps comparisons easy and avoids UI-specific assumptions early in the algorithm.
Step 1: Sort Events
Sort events by start time, and break ties by end time. This gives a stable order for building overlap groups and columns.
This is the natural first step because interval layout depends on chronological order.
Step 2: Build Overlap Groups
Events that overlap directly or indirectly belong to the same layout group. For example, if event A overlaps B and B overlaps C, all three must be considered together even if A and C do not touch directly.
You can form groups with a sweep:
Each group can now be laid out independently. That is useful because width calculations do not need to consider events that are completely disjoint in time.
Step 3: Assign Columns Greedily
Within one group, assign each event to the first column whose latest event has already ended. If no column is free, open a new column.
This greedy strategy is standard for interval partitioning and produces the minimum number of columns for the group.
Step 4: Expand Events To Maximum Width
If you stop after column assignment, every event gets width 1 / column_count, but that is not maximum width. Some events can span into later columns if those columns are empty during the event's time range.
So for each event, scan columns to the right until you find one containing an overlapping event:
Now an event in column 0 might occupy two or three columns worth of width if the later columns are free during its time interval.
Convert Layout To UI Frames
Once you know the group column count, each event's column index, and its span, converting to UI geometry is straightforward:
- '
topandheightcome from time' - '
leftcomes fromcolumn_index / column_count' - '
widthcomes fromspan / column_count'
That gives the maximum-width layout pattern seen in many day-view calendars.
Why This Works
The greedy column assignment solves the conflict-separation problem. The expansion pass solves the wasted-space problem. Without expansion, narrow events often leave empty white gaps to the right even when no conflict exists there. The expansion step is what upgrades a merely correct overlap layout into the more polished "maximum width" layout users expect.
Common Pitfalls
One common mistake is grouping only directly overlapping neighbors and missing transitive overlap groups. Another is assigning equal width to every event in the group and stopping there, which wastes space. Developers also often mishandle boundary conditions such as one event ending exactly when another begins. In most calendar UIs, that should count as non-overlapping, so end <= next.start is the safe comparison. Finally, if all layout logic is tied too early to pixel values, debugging becomes harder. Keep the algorithm in abstract columns and spans first, then map it to rendering coordinates.
Summary
- Treat calendar events as intervals and sort them by start time.
- Group events that overlap directly or indirectly.
- Assign columns greedily to separate conflicting events.
- Expand each event horizontally into later free columns to achieve maximum width.
- Convert the final column index and span into screen coordinates only after the interval layout is known.

