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...