JS - узнает видимый процент скрытого элемента DOM - PullRequest
0 голосов
/ 23 мая 2018

Редактировать Следующие HTML и CSS являются просто примером , реальный вариант использования включает в себя сложный DOM и должен быть достаточно универсальным для работы на разных веб-страницах.Единственное верное предположение состоит в том, что все элементы являются прямоугольными.


С учетом следующего:

HTML

<div class="a" id="a">
A
</div>
<div class="b">
B
</div>
<div class="c">
  C
  <div class="d">
  D
  </div>
</div>

CSS

.a,.b,.c,.d{
  border: solid 1px black;
  opacity: 0.5;
  font-family: arial;
  position: absolute;
  font-size: 20px;
}

.a{
  width:300px;
  height:250px;
  top:30px;
  left:20px;
  background:green;
}

.b{
  width:300px;
  height:145px;
  top:10px;
  left:20px;
  background:blue;
}
.c{
  width:150px;
  height:300px;
  top:30px;
  left:60px;
  background:red;
}
.d{
  margin:10px;
  background:yellow;
  width:100px;
  height:200px
}

производитследующий результат:
enter image description here


Я пытаюсь определить процент DIV "A", который не скрыт другими элементами, т.е.% в данном примере.

Я написал следующий JS ( fiddle ), который сканирует прямоугольную область "A" DIV и собирает затемняющие элементы.

let el = document.getElementById("a");
let rect = el.getBoundingClientRect();
let right = rect.x + rect.width;
let bottom = rect.y + rect.height;
let elements = [];
for (let i = rect.x; i < right; i += 10) {
  for (let j = rect.y; j < bottom; j += 10) {
    let sampled = document.elementFromPoint(i, j);
    if (sampled && sampled !== el && elements.indexOf(sampled) === -1) {
      elements.push(sampled);
    }
  }
}

Теперь я пытаюсь найти наиболее эффективный способ сделать расчеты.Я попробовал другой способ сканирования прямоугольного пикселя за пикселем и подсчитать все пиксели, которые не являются частью основного DIV, однако этот подход оказался медленным для принятого решения.

Любая помощь будет принята с благодарностью.

ОБНОВЛЕНИЕ
После некоторых исследований я начинаю думать, что мне понадобится алгоритм строчной развертки, но я все еще не совсем уверен, как изменить код для решения моей проблемы.

Обновление 2
При использовании pointer-events: none; подход document.elementFromPoint не будет работать, поэтому я ищу лучшее решение.

Ответы [ 4 ]

0 голосов
/ 28 мая 2018

Настроив ваше первоначальное решение, идея заключалась в том, чтобы удалить стиль событий указателя при использовании метода elementFromPoint.

function addCSS(){
    let style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = '* {pointer-events: all !important;}';
    document.getElementsByTagName('head')[0].appendChild(style);

    Array.prototype.filter.call(document.querySelectorAll("[style]"),(node)=>{
      return node.style.pointerEvents;
    }).forEach((node)=>{
      node.style.pointerEvents = "all";
    })
}

см. скрипка

0 голосов
/ 27 мая 2018

Вы можете использовать Intersection Observer, чтобы получить видимый процент элемента в родительском элементе.

https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

Это экспериментально!

0 голосов
/ 27 мая 2018

Вы можете перебрать все элементы dom и собрать затемняющие элементы.Это дало бы сложность O(n), где n = количество элементов вместо O(x * y), где x и y - ширина пикселя и высота div, соответственно.

let el = document.getElementById("a");
let rect = el.getBoundingClientRect();
let right = rect.x + rect.width;
let bottom = rect.y + rect.height;
let baseDepth = parseFloat(el.style.zIndex);
if (baseDepth === NaN) {
  baseDepth = 0;
}
let all = document.getElementsByTagName("*");
let obscuringElements = [];
for (var i=0, max=all.length; i < max; i++) {
    let sample = all[i];
    if (sample !== el && elements.indexOf(sample) === -1) {
      let subRect = sample.getBoundingClientRect();
      if (subRect.x <= right && subRect.x + subRect.width >= rect.x
        && subRect.y <= bottom && subRect.y + subRect.height >= rect.y) {
          obscuringElements.push(sample);
        }
    }
}

ТеперьВы можете использовать ограничивающие фрагменты obscuringElements, чтобы выяснить, сколько из el видно.

0 голосов
/ 27 мая 2018

Я думаю, я бы попробовал другой подход.

Допущения:

  1. при условии, что все элементы являются прямоугольниками
  2. при условии, что все элементы имеют z-index вышечем A

Я хотел бы:

  1. получить прямоугольник элемента контекста (то есть элемент DOM, который является первым родителем обоих: Aэлемент и все те, которые могут скрывать A)
  2. перечислить все его дочерние элементы, которые могут скрывать A (поэтому все, кроме A)
  3. получают ограничивающий прямоугольник для каждого из них
  4. сортируйте те, которые имеют z-index выше, чем A элемент, по: верхним, правым, нижним и левым координатам
  5. , как только у вас есть верхние, правые, нижние, левые - большинство координат скрывающих вас элементовВы можете вычесть их из ваших A координат прямоугольника и вычислить площадь

для многих потенциально затененных элементов, которые вы можете дополнительно оптимизировать, удалив шаг сортировки, но вместо этого следите за верхним / правым / нижним / левым-самым крайнимкоординаты при переборе obsвылечить элементы и обновить их, если в настоящее время повторяется, один больше в любом направлении.

...