3
\$\begingroup\$

I know you can calculate if an element is overlapping another by comparing the top|bottom|right|left properties within the getBoundingClientRect method. However, you need to loop through the elements to do so. I'm curious to know what is the performant way of checking to see if an element is overlapping any other element. For example, checking to see if label one is overlaying any other element. Then checking to see if label two is overlapping any other element including label one without using a loop each time, or is this the only way? Currently I'm just checking one element against the previous.

// dismiss -- just creating less CSS
const randomColor = "#" + ((1 << 24) * Math.random() | 0).toString(16);
document.querySelectorAll('.label').forEach((x, i) => {
  document.querySelectorAll('.label')[i].style.background = "#" + ((1 << 24) * Math.random() | 0).toString(16);
});

//function to check for overlapping
function overlayCheck() {
  let points = document.querySelectorAll('.label');
  let rightPos = (elem) => elem.getBoundingClientRect().right;
  let leftPos = (elem) => elem.getBoundingClientRect().left;
  let topPos = (elem) => elem.getBoundingClientRect().top;
  let btmPos = (elem) => elem.getBoundingClientRect().bottom;

  for (let i = 1; i < points.length; i++) {
    if (!(
        rightPos(points[i]) < leftPos(points[i - 1]) ||
        leftPos(points[i]) > rightPos(points[i - 1]) ||
        btmPos(points[i]) < topPos(points[i - 1]) ||
        topPos(points[i]) > btmPos(points[i - 1])
      )) {
      points[i].innerHTML = `${points[i].innerHTML} C`;
    }
    if (i === points.length - 1) {
      return
    }
  }
}

overlayCheck();
.parent {
  position: relative;
  display: flex;
}

.label {
  height: 75px;
  left: 0;
  width: 100px;
  margin-left: 10px;
  background-color: orange
}

.cover {
  width: 220px;
  position: absolute;
  left: 0;
  height: 50px;
  bottom: 0;
}
<div class="parent">
  <div class="label cover">Label 1</div>
  <div class="label">Label 2</div>
  <div class="label">Label 3</div>
  <div class="label">Label 4</div>
  <div class="label">Label 5</div>
  <div class="label">Label 6</div>
</div>

\$\endgroup\$
  • \$\begingroup\$ Does your code work correctly? It does not detect that “Label 1” overlaps with “Label 3”. Or am I misunderstanding the task? \$\endgroup\$ – Martin R Feb 14 at 8:43
  • \$\begingroup\$ Voted to close. The code you provided does not do what you want it to do. \$\endgroup\$ – konijn Feb 14 at 14:26
1
\$\begingroup\$

I figured out a way thru trial and error. I'll post this here for anyone else who could use it.

// dismiss -- just creating less CSS
const randomColor = "#" + ((1 << 24) * Math.random() | 0).toString(16);
document.querySelectorAll('.label').forEach((x, i) => {
  document.querySelectorAll('.label')[i].style.background = "#" + ((1 << 24) * Math.random() | 0).toString(16);
});

//function to check for overlapping
function overlayCheck() {
  let points = document.querySelectorAll('.label');
  let rightPos = (elem) => elem.getBoundingClientRect().right;
  let leftPos = (elem) => elem.getBoundingClientRect().left;
  let topPos = (elem) => elem.getBoundingClientRect().top;
  let btmPos = (elem) => elem.getBoundingClientRect().bottom;

  for (let i = 0; i < points.length; i++) {
    for (let j = 0; j < points.length; j++) {
      let isOverlapping = !(
        rightPos(points[i]) < leftPos(points[j]) ||
        leftPos(points[i]) > rightPos(points[j]) ||
        btmPos(points[i]) < topPos(points[j]) ||
        topPos(points[i]) > btmPos(points[j])
      );

      if (isOverlapping && j !== i) {
        points[i].innerHTML = `${points[i].innerHTML} C`;
      }
    }
  }
}
overlayCheck();
.parent {
  position: relative;
  display: flex;
}

.label {
  height: 75px;
  left: 0;
  width: 100px;
  margin-left: 10px;
  background-color: orange
}

.cover {
  width: 220px;
  position: absolute;
  left: 0;
  height: 50px;
  bottom: 0;
}
<div class="parent">
  <div class="label cover">Label 1</div>
  <div class="label">Label 2</div>
  <div class="label">Label 3</div>
  <div class="label">Label 4</div>
  <div class="label">Label 5</div>
  <div class="label">Label 6</div>
</div>

| improve this answer | |
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.