JS - 找出隐藏的DOM元素的可见百分比

时间:2018-05-23 11:55:43

标签: javascript html css intersection

编辑以下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

我试图检测&#34; A&#34;的百分比。不被其他元素遮挡的DIV,IE:在给定示例中为25%。

我已经编写了以下JS(fiddle)来扫描&#34; A&#34; 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 :(得分:1)

您可以使用self.present()获取父级中元素的可见百分比..

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

虽然这是实验性的!

答案 1 :(得分:1)

调整初始解决方案时,我们的想法是在使用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";
    })
}

请参阅此fiddle

答案 2 :(得分:0)

我想我会尝试不同的方法。

假设:

  1. 假设所有元素都是矩形
  2. 假设所有元素都z-index高于A
  3. 我会:

    1. 获取上下文元素矩形(即,作为两者的第一个父元素的DOM元素:A元素以及可能隐藏A的所有元素
    2. 列出所有可能会掩盖A的孩子(所以除了A之外的所有孩子)
    3. 为每个人获取边界矩形
    4. 将那些z-index元素高于A的元素排序:top,right,bottom&amp;左坐标
    5. 一旦你有顶部,右边,底部,左边 - 遮挡元素的大多数坐标,你可以从A矩形坐标中减去那些并计算面积
    6. 对于许多可能模糊的元素,您可以通过删除排序步骤进一步优化,而是在迭代模糊元素时跟踪顶部/右侧/底部/最左侧坐标,并在当前迭代时更新它们在任一方向上更多。

答案 3 :(得分:0)

你可以遍历所有 dom元素并收集模糊的元素。这会给出O(n)的复杂性,其中n =元素数而不是O(x * y),其中xy分别是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的可见范围。