凸壳(路径)中的svg元素?

时间:2014-11-27 18:58:20

标签: javascript svg d3.js

我有一个可以绘制的svg路径。使用d3js我使用d3.geom.hull(...)计算路径周围的凸包。现在我有一些svg对象,如节点(svg:circle),我想知道节点是否在船体内。我怎么能意识到这一点?这是我的svg视图中的图片:

View of the SVG

修改 我的目标是船体中的节点元素(在路径内),而不仅仅是在路径的边缘。

2 个答案:

答案 0 :(得分:1)

这是一种简单的方法:

  1. 计算你的船体几何,找回d3.geom.hull给你的坐标数组。

  2. 将新点添加到原始数据数组,并在此数组上再次计算d3.geom.hull。

  3. 将步骤1返回的点数组与步骤2返回的点数组进行比较,以查看计算出的船体是否已更改。如果有,那么该点在凸包外面。如果没有变化,则它在凸包内。

  4. 如果你有一个非常大的数据集,这可能是性能密集型的。

    以下是一些简单的代码来演示:

       // Some Random points
       var coords = d3.range(50).map(function() {return [Math.random(),Math.random()]})
       yourHull = d3.geom.hull(coords)
       // Random new point
       newCoord = [Math.random(),Math.random()]
       coords.push(newCoord)
       newHull = d3.geom.hull(coords)
    
       //The easy case to spot
       if (newHull.length != yourHull.length) {
          console.log("Outside")
       }
       //If the array lengths are the same, the point values may have changed
       else {
       var outside = false;
       for (var x = 0; x < yourHull.length;x++) {
          for (var y = 0; y < 2;y++) {
             if (yourHull[x][y] != newHull[x][y]) {
                outside = true;
                break;
             }
          }
       }
    
       if (outside) {
          console.log("outside")
       }
       else {
          console.log("on the hull")
       }
      }
    

答案 1 :(得分:1)

最快的方法是让浏览器完成所有实际工作。特别是,使用方法document.getElementFromPoint()让渲染引擎确定重叠。

这个想法很简单 - 添加你对后面船体感兴趣的点,然后检查上面的方法是否给你点或船体。代码看起来像这样。

function isInside(point) {
  var c = svg.insert("circle", "path.hull")
    .attr("r", 1)
    .attr("cx", point[0])
    .attr("cy", point[1]);

  var bounds = c.node().getBoundingClientRect();

  var atPoint = document.elementFromPoint(bounds.left, bounds.top);
  var inside = atPoint == c.node() ? false : true;

  c.remove();

  return inside;
}

唯一稍微棘手的一点是将点的相对坐标转换为绝对坐标 - 上面的代码假定SVG是页面本身的顶级元素或者不是由包含元素转换的。如果不是这种情况,请根据需要调整代码。

与其他答案相比,最大优势是运行时不依赖于船体的大小(如定义它的点数)。它只取决于您要检查的点数。

完整演示here