JSFiddle - React, Tailwind, and code Playground
by lid0
HTML
<pre>
process overlap of blocks and push overlaps down a line until no overlaps on all lines.
we start with a flat list of items.
</pre>
<div id="container" style="position:relative">
</div>
CSS
.line {
background: #cfcfcf;
border: 1px solid gray;
height: 30px;
}
.box {
opacity: 0.8;
color: white;
font-size: 12px;
margin-top: 3px;
display: inline-block;
border: 1px solid black;
background: #246222;
width: 10px;
height: 20px;
position: absolute;
}
/** **/
.line:nth-child(2) .box:nth-child(odd) {
margin-top: 5px;
background: red;
}
.message.before {
margin-top:10px;
background:yellow;
}
.message.after {
margin-top:10px;
background:yellow;
}
JavaScript
/**
@author: lidlanca 2021 march 29
process a list of items.
list must be ordered by x property in ASC order.
item requires {x,w} properties.
the function will return the items in lines.
where overlapping items are pushed down to the next line until there are not overlapps.
Given a list of items:
[ {id:A, x:0, w:10}, {id:B,x:7,w:10} ]
processItems() will return:
[
[{id:A, x:0, w:10}],
[{id:B, x:7, w:10} ]
]
Which can then visually be rendered |---A---| and |---B---| before processing:
|---A--|-|--B---|
and after processing, line by line rendering
|---A---|
|---B---|
**/
function processItems(items) {
var lines = []
var done = false
var line = [...items] // start with the whole list of items
do {
done = true
// each iteration we will process the last line, and populate
// items that can stay in the line into currentLine
// and items that overlap push to the next line.
var currentLine = []
var nextLine = []
// if the line we are processing has one or less items.
// we break, there are no processing to do.
if (line.length <= 1 && lines.length > 0) {
if (lines.length == 0) {
// if its the first line we are processing, we need to add the line to the result object
// and then we can exit.
lines.push(line)
}
break
}
// push first element of the line to currentLine
currentLine.push(line[0])
var prevNonOverlap = line[0] // initialize as first non overlapping item of the line
// iterate on the remainin items of the line.
for (i = 1; i < line.length; i++) {
// check if current item overlap with last non overlapping item.
if (
itemsIntersect(prevNonOverlap, line[i])
/* prevNonOverlap.x + prevNonOverlap.w >= line[i].x &&
prevNonOverlap.x + prevNonOverlap.w <= line[i].x + line[i].w */
) {
// item overlap with last non overlapping item. push item to nextLine.
...