Implement readingOrderII(elements) — take a list of positioned boxes scattered on a 2D canvas and return them in the order a person would read them: top rows first, left to right within each row. This is the follow-up to Reading Order, where every box sat on an exact pixel row. Real layouts are messier: two boxes meant to share a line are often off by a pixel or three, so you can't group rows by an exact y. The twist here is the rule for "same row": two boxes belong to the same row when their vertical extents overlap, which tolerates that small misalignment. Each box is a plain data object with coordinates — not a real DOM node — so there is no layout engine to lean on; the grouping is yours to compute from the numbers.
type Box = {
id: string; // a label so you can identify each box in the output.
x: number; // distance from the left edge of the canvas, in pixels.
y: number; // distance from the top edge of the canvas, in pixels.
width: number; // box width, in pixels.
height: number; // box height, in pixels — defines the box's vertical extent.
};
// Returns a NEW array of the SAME box objects, ordered for reading.
// Does not mutate the input array or any box.
function readingOrderII(elements: Box[]): Box[];
Two boxes a and b share a row when their vertical extents overlap:
a.y < b.y + b.height && b.y < a.y + a.height
// Two boxes nudged out of alignment (y of 0 and 3) still overlap vertically,
// so they read as one row, left to right by x.
readingOrderII([
{ id: 'right', x: 200, y: 3, width: 40, height: 20 },
{ id: 'left', x: 0, y: 0, width: 40, height: 20 },
]);
// → ids in order: ['left', 'right']
// A clear vertical gap (top ends at y:20, bottom starts at y:60) means two rows.
// The whole top row comes out before the bottom row.
readingOrderII([
{ id: 'A', x: 0, y: 0, width: 40, height: 20 },
{ id: 'B', x: 100, y: 0, width: 40, height: 20 },
{ id: 'C', x: 0, y: 60, width: 40, height: 20 },
{ id: 'D', x: 100, y: 60, width: 40, height: 20 },
]);
// → ids in order: ['A', 'B', 'C', 'D']
y. Use a.y < b.y + b.height && b.y < a.y + a.height. This is what lets a row survive a few pixels of misalignment — the defining difference from the exact-row base problem.a.y + a.height === b.y) — do not overlap, so they are different rows.x ascending. A box higher on the page reads before a box lower down only when they are in different rows; inside one row, horizontal position decides.x orders within it. Empty input returns [].