/** * Returns a compact layout of a list of intervals * * Second options parameter * - `tight` places an interval with same ending as previous next to each other. */ export function layoutIntervals(intervals, { tight } = {}) { tight ??= true const canPlaceInterval = tight ? ({ start }, place) => place <= start : ({ start }, place) => place < start if (intervals.length === 0) { return [] } // sort intervals by ".start" intervals.sort((a, b) => a.start - b.start) const stack = [{ lastEnd: -Infinity, intervals: [] }] for (const interval of intervals) { const s = stack.find(level => canPlaceInterval(interval, level.lastEnd)) if (s) { s.intervals.push(interval) s.lastEnd = Math.max(s.lastEnd, interval.end) } else { stack.push({ lastEnd: interval.end, intervals: [interval] }) } } return stack.map(({ intervals }) => intervals) } // // // // Testing... // // // console.dir( // layoutIntervals([ // { start: 0, end: 2 }, // { start: 2, end: 4 }, // { start: 1, end: 3 }, // { start: 4, end: 6 }, // { start: 3, end: 5 }, // { start: 2, end: 4 }, // ]), // { depth: null } // )