JSFiddle - React, Tailwind, and code Playground
by lid0
HTML
<template id="line_component_template">
<div class="line">
<div
v-for="item in items" :key="item.id"
class="box" :style=`width:${item.w}px;left:${item.x}px`>
{{item.id}}
</div>
</div>
</template>
<pre>solve overlapping boxes. solve by pushing items down a line if they intersect
with a box to thier left. vue ui</pre>
<div id="app">
Before:
<line-component :items=items></line-component>
<hr>
After:
<line-component v-for="line in lines" :items=line></line-component>
</div>
CSS
.box {
position:absolute;
background:#246222;
color:#fff;
border:1px solid black;
display:inline-block;
height:20px;
}
.line {
position:relative;
display:list-item;
border:1px solid gray;
background:#dfdfdf;
padding:5px;
}
JavaScript
import {createApp,defineComponent,provide, inject,ref} from "https://unpkg.com/[email protected]/dist/vue.esm-browser.js";
// author: Lidlanca 2021 april 1
// based on implementation
// https://jsfiddle.net/lid0/b3m5ro0f/
// but simplified, slightly less efficient logic, by using filter instead of managing array for current line and next line.
// also using vue for view/UI logic.
var id = 0;
var Id = () => id++
var items=[
{w:10,x:0,id:Id()},
{w:15,x:5,id:Id()},
{w:30,x:15,id:Id()},
{w:20,x:56,id:Id()},
{w:30,x:60,id:Id()},
{w:30,x:50,id:Id()},
{w:55,x:110,id:Id()}
];
function itemsIntersect(a, b) {
return (a.x <= b.x && b.x < (a.x + a.w)) ||
(b.x + b.w > a.x && (b.x + b.w) <= (a.x + a.w))
}
function sortItemsByX(items) {
items.sort(function(a, b) {
if (a.x === b.x) return 0
return a.x < b.x ? -1 : 1
})
}
// set all items .line to the given line number.
function setItemsLine(items,line){
return items.forEach( (item) => { item.line = line } )
}
// return only items in the given line number.
function filterByLine(items,line){
return items.filter(item=> (item.line ??0)== line)
}
//process items to lines. overlapping items are pushed down a line until no overlap on any line.
function process(items){
var items = JSON.parse(JSON.stringify(items)) // clone to prevent mutation
var currentLineNumber = 0
let done = true;
var lines = []
var line_items = items;
do {
done=true;
var prev = line_items[0]
for(let i=1;i<line_items.length;i++){
if(itemsIntersect(prev,line_items[i])){
line_items[i].line++
done=false
} else {
prev = line_items[i]
}
}
lines.push(filterByLine(items,currentLineNumber)) // we done with this line add it to lines.
currentLineNumber++ // increment line number for next iteration
line_items = filterByLine(items,currentLineNumber) // filter items for the next line we are going to process.
} while(!done)
return...