Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 55x 55x 55x 55x 55x 55x 98x 98x 67x 31x 31x 55x 55x 55x 111x 6x 6x 6x 111x 111x 111x 111x 111x 12x 12x 12x 12x 111x 111x 111x 99x 111x 111x 111x 80x 111x 55x 55x 55x 37x 55x 55x 55x 55x 55x 55x 55x 1x 43x 43x 99x 111x 111x 111x 111x 99x 43x 43x 1x 111x 111x 111x 111x 111x 111x 111x 68x 68x 68x 68x 68x 68x 68x 6x 111x 111x 1x 167x 167x 167x | interface Dimension {
readonly min: number;
readonly max: number;
}
export interface LaneLayoutEntry<T> {
readonly data: T;
readonly dimension: Dimension;
readonly lane: { startLane: number; endLane: number; maxLane: number };
}
export interface LaneLayout<T> {
get maxLanes(): number;
readonly entries: readonly T[];
}
export function computeLaneLayout<T extends LaneLayoutEntry<unknown>>(
layoutEntries: T[],
): LaneLayout<T> {
let lanes: LaneLayoutEntry<unknown>[][] = [];
let lastEnding: number | null = null;
const rv: T[] = [...layoutEntries].sort((e1, e2) => {
const rv = e1.dimension.min - e2.dimension.min;
if (rv !== 0) {
return rv;
}
return e1.dimension.max - e2.dimension.max;
});
rv.forEach(e => {
if (lastEnding !== null && e.dimension.min >= lastEnding) {
computeLanes(lanes);
lanes = [];
lastEnding = null;
}
let placed = false;
for (const col of lanes) {
if (!intersects(col[col.length - 1].dimension, e.dimension)) {
col.push(e);
placed = true;
break;
}
}
if (!placed) {
lanes.push([e]);
}
if (lastEnding === null || e.dimension.max > lastEnding) {
lastEnding = e.dimension.max;
}
});
if (lanes.length > 0) {
computeLanes(lanes);
}
return {
get maxLanes() {
return rv
.map(e => e.lane.maxLane)
.reduce((a, b) => Math.max(a, b), -Infinity);
},
entries: rv,
};
}
function computeLanes(lanes: LaneLayoutEntry<unknown>[][]) {
lanes.forEach((lane, index) => {
lane.forEach(layoutEntry => {
const colSpan = computeLaneSpan(layoutEntry, index, lanes);
layoutEntry.lane.startLane = index;
layoutEntry.lane.endLane = index + colSpan;
layoutEntry.lane.maxLane = lanes.length;
});
});
}
function computeLaneSpan(
layoutEntry: LaneLayoutEntry<unknown>,
laneIndex: number,
columns: LaneLayoutEntry<unknown>[][],
) {
let colSpan = 1;
for (let i = laneIndex + 1; i < columns.length; i++) {
const col = columns[i];
for (const e of col) {
if (intersects(layoutEntry.dimension, e.dimension)) {
return colSpan;
}
}
colSpan++;
}
return colSpan;
}
function intersects(a: Dimension, b: Dimension) {
return a.max > b.min && a.min < b.max;
}
|