D3.js 如何在D3中生成覆盖不同大小节点的凸包

D3.js 如何在D3中生成覆盖不同大小节点的凸包,d3.js,social-networking,convex-hull,D3.js,Social Networking,Convex Hull,我遇到了D3凸包实现的另一个限制:它不适应节点的大小。嗯,我没想到它会自动完成,但这似乎是人们使用D3.js的数据可视化的一个相当标准的方面,所以我希望找到一个解决方案。我还没有找到这样的解决办法 一个明显且不令人满意的解决方案是找到组中最大节点的大小,并将其设置为船体的冲程宽度。不幸的是,这看起来很糟糕,因为节点大小是高度可变的 我试图扩展插入假点的思想,以解释有1或2个成员的组。在本例中,我为每个节点添加了四个点,它们位于节点的N、S、E和W边界 var groupPath = functi

我遇到了D3凸包实现的另一个限制:它不适应节点的大小。嗯,我没想到它会自动完成,但这似乎是人们使用D3.js的数据可视化的一个相当标准的方面,所以我希望找到一个解决方案。我还没有找到这样的解决办法

一个明显且不令人满意的解决方案是找到组中最大节点的大小,并将其设置为船体的冲程宽度。不幸的是,这看起来很糟糕,因为节点大小是高度可变的

我试图扩展插入假点的思想,以解释有1或2个成员的组。在本例中,我为每个节点添加了四个点,它们位于节点的N、S、E和W边界

var groupPath = function(d) {
var fakePoints = [];  // This adjusts convex hulls for groups with fewer than 3 nodes by adding virtual nodes.
if (d.length == 1 || d.length == 2) {
   fakePoints = [ [d[0].x + 0.001, d[0].y - 0.001],
                  [d[0].x - 0.001, d[0].y + 0.001],
                  [d[0].x - 0.001, d[0].y + 0.001]]; }     
   return "M" + 
   d3.geom.hull(d.map(function(i) { return [
        [(i.x), (i.y + (2 + (4 * i.propertyValue)))],
        [(i.x + (2 + (4 * i.propertyValue))), (i.y)],
        [(i.x), (i.y - (2 + (4 * i.propertyValue)))],
        [(i.x - (2 + (4 * i.propertyValue))), (i.y) ]]; })
      .concat(fakePoints))  //do not forget to append the fakePoints to the input data
      .join("L") 
      + "Z";
};
…其中
(2+(4*i.propertyValue))
是节点的半径。然后我让笔划宽度正好是从节点边缘到凸面外壳外缘的距离…填充。这似乎是个好主意,但完全行不通。结果非常令人费解,因为它甚至没有创建这些点的凸包……而且顺序很重要。您可以看到它在中的实际作用

我首先认为伪点是问题的根源,也许它们在某种程度上是,但是如果你移除它们,凸包就不适用于有1或2个节点的组…这很奇怪,因为我认为我已经在凸包的输入中添加了4个点。一种(可能的)可能性是,我没有以正确的方式添加这四点,但我不知道与此不同的是,什么方式是正确的方式


也许有一个简单的方法可以解决这个问题,对于那些更了解D3是如何创建凸面外壳的人来说。也就是说,可能有人可以看到我的方法有什么问题并帮助我修复它,或者可能有人已经有了一个完全更好的方法来解决这个问题。

我以前尝试的问题是由于对
d3.geom.hull
函数中的四个虚拟点使用map函数造成的。这将创建嵌套的点阵列,而不是简单的点列表。我找不到javascript的“展平”函数,所以我使用
forEach()
将点放在
d3.geom.hull
函数之外,然后像这样输入它们:

var groupPath = function(d) {
    var fakePoints = [];  
    d.forEach(function(element) { fakePoints = fakePoints.concat([  // "0.7071" is the sine and cosine of 45 degree for corner points.
       [(element.x), (element.y + (2 + (4 * element.propertyValue)))],
       [(element.x + 0.7071 * (2 + (4 * element.propertyValue))), (element.y + 0.7071 * (2 + (4 * element.propertyValue)))],
       [(element.x + (2 + (4 * element.propertyValue))), (element.y)],
       [(element.x + 0.7071 * (2 + (4 * element.propertyValue))), (element.y - 0.7071 * (2 + (4 * element.propertyValue)))],
       [(element.x), (element.y - (2 + (4 * element.propertyValue)))],
       [(element.x - 0.7071 * (2 + (4 * element.propertyValue))), (element.y - 0.7071 * (2 + (4 * element.propertyValue)))],
       [(element.x - (2 + (4 * element.propertyValue))), (element.y)],
       [(element.x - 0.7071 * (2 + (4 * element.propertyValue))), (element.y + 0.7071 * (2 + (4 * element.propertyValue)))]
       ]); 
    })
    return "M" + d3.geom.hull( fakePoints ).join("L") + "Z";
};
如您所见,这是通过为每个节点添加8个点来实现的,因此凸包从每个方向都是圆形的。这样做还可以消除向拥有1或2个成员的组添加伪造点的需要。虽然它仍然不像普通的示例那样好看,但是不适合节点大小,如果有必要的话,可以为您的案例改进美学效果

有一个具有多层组的工作示例,这样每个组的凸面外壳围绕并适应节点的大小。这种可视化仍然需要在其他方面进行工作(例如重新绘制外壳上的边缘,并使链接长度与组成员身份相适应),但这些是其他问题。这个问题已经解决了,但我仍然愿意看到一个更好的答案或者这个问题的改进版本