DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

Four of the Six Wrong Calendar Layouts Produce Zero Overlapping Boxes, Which Is the Only Thing Anyone Tests

A day view puts overlapping meetings side by side. Underneath it is interval-graph colouring: cluster the day, give every event the lowest free column, then let each one expand rightwards over the columns nothing blocks.

Drag the events around and watch the checkers run: https://dev48.infy.uk/design/day67-event-layout.html

Greedy is optimal in exactly one order

Place events one at a time into the lowest-numbered column with nothing conflicting in it. Sorted by start time this is provably optimal: everything already placed that conflicts is live at that instant, so those events pairwise overlap and occupy that many distinct columns. Take the sort away and the argument evaporates.

11:15-12:15   11:45-13:00   12:45-13:45   13:30-15:00

most at once (sweep line): 2

by start time :  2 columns, 0 overlaps, mean width 50.0%
in array order:  3 columns, 0 overlaps, mean width 41.7%
Enter fullscreen mode Exit fullscreen mode

Never more than two meetings at once, so two columns is optimal. Array order spends three, with no overlap, no error, and three of the four boxes a third narrower. This is exactly the line that gets refactored away in a cleanup: it looks decorative, and removing it breaks nothing you can see.

Interval graphs are perfect, so there is a free oracle

χ = ω here: the minimum number of columns equals the largest number of events happening at one instant. Not an approximation — an identity. Which gives a sweep line sharing no code with the layout.

pts.sort((p,q) => p.t - q.t || p.d - q.d);   // ends before starts at equal t
Enter fullscreen mode Exit fullscreen mode

That || p.d - q.d is the half-open rule: at 10:00 the meeting that ends must be counted out before the one that starts is counted in.

The column that matters, over 12,000 schedules

variant days with overlapping boxes days using extra columns mean width
correct 0 0 41.9%
no expansion 0 0 39.6%
closed intervals 0 3,417 (28.5%) 37.0%
columns in array order 0 865 (7.2%) 41.5%
longest event first 0 334 (2.8%) 42.2%
cluster against previous end 4,954 0 43.9%
expand without checking 11,414 0 74.0%

Four of the six wrong versions never produce a single overlapping box. The one property everyone tests cannot see them; they are narrower, not broken. The two that are visible break on 41% and 95% of days and would never have shipped anyway.

Mean width does not rank them either: longest-first spends an extra column on 2.8% of days and still reads marginally wider on average, because the days it gets wrong are not the days that dominate the mean.

What the measurement killed

Expansion was going to be sold as the thing that makes the layout look right rather than merely be right. Measured, it widens 6.2% of events, and those get 2.7× wider. The mechanism says why: expansion is a whole-event property, so one blocked minute anywhere stops a meeting expanding for its entire duration, and in a dense cluster almost every minute is blocked somewhere.

The assertion I care about most is the one that says the bugs are invisible:

assert(arrayOrder.extraColumnCases > 0);
assert(arrayOrder.collisionCases === 0);        // <- the point of the whole page
Enter fullscreen mode Exit fullscreen mode

A wrong version that fails the obvious test is not dangerous; it never ships. If that second line ever starts failing, the harness has drifted, not the bug.

Part of a from-scratch series — one component a day, vanilla JS, one file, offline: https://dev48.infy.uk/designfromzero.php

Top comments (0)