我遇到了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))
是节点的半径。然后,我将笔划宽度设置为从节点边缘到凸包的外边缘……填充的距离。这似乎是个好主意,但完全无效。结果非常令人困惑,因为它甚至没有创建这些点的凸包...而且顺序很重要。您可以在此JSFiddle中看到它的实际作用。
我首先以为假点是造成问题的原因,也许是某种原因,但是如果将其删除,则凸包不适用于具有1或2个节点的组...这很奇怪,因为我认为我已经将4点添加到凸包的输入。一种(可能)的可能性是,我没有以正确的方式添加这四个点,但是我不知道哪种方法与正确的方法不同。
对于某些更好地了解D3如何创建凸包的人来说,可能有一个简单的解决方案。就是说,也许有人可以看到我的方法有什么问题并帮助我解决它,或者也许有人已经有了一种更好的方法。
我先前尝试的问题是由于对函数内部的四个虚拟点使用了map函数引起的d3.geom.hull
。这将创建点的嵌套数组,而不是简单的点列表。我找不到适用于javascript的“展平”函数,因此我使用将这些点放到d3.geom.hull
函数外部,forEach()
然后像这样输入它们:
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个成员的组添加fakePoints的需要。尽管它看起来不如不适应节点大小的普通示例好看,但如果有必要,可以针对您的情况改进美观性。
这个JSFiddle有一个工作示例,其中包含多层组,以便每个组的凸包环绕并适应节点的大小。这种可视化仍然需要在其他方面进行工作(例如在船体上重绘边缘,并使链接长度适应组成员身份),但这是其他问题。这个问题已经解决,但我仍然愿意看到一个更好的答案或对此版本的改进版本。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句