如何使一个凸包覆盖D3中不同大小的节点 [英] How to make a convex hull covering differently sized nodes in D3

查看:191
本文介绍了如何使一个凸包覆盖D3中不同大小的节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了D3的凸包实现的另一个限制:它不会调整到节点的大小。好吧,我没想到它会自动这样做,但这似乎是一个相当标准的方面,数据可视化人们使用D3.js,所以我希望找到一个修复。我没有找到这样的修复。

I've run across another limitation of the convex hull implementation of D3: it does not adjust to the size of the nodes. Well, I didn't expect that it would do so automatically, but this seems like a fairly standard aspect of the data visualizations people are using D3.js, so I expected to find a fix for it. I have not found such a fix.

一个明显和不令人满意的解决方案是找到组的最大节点的大小,并将其设置为船体。不幸的是,这看起来很可怕,那么节点大小是高度可变的。

One obvious and unsatisfactory solution is to find the size of the largest node of the group and set that as the stroke-width of the hull. Unfortunately that looks terrible then the node sizes are highly variable.

我试图扩展插入假点的思考来解释1或2个成员的组。在这种情况下,我为每个节点添加了四个点,它们位于节点的N,S,E和W边界。

I've tried to extend the thinking of inserting fake points to account for groups with 1 or 2 members. In this case I added four points per node that are located at the N,S,E, and W boundaries of the node.

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 中看到它的实际效果。

...in which (2 + (4 * i.propertyValue)) is the radius of the node. Then I made the the stroke width just the distance from the edge of the node to the outer edge of the convex hull...the padding. This seemed like a good idea, but it TOTALLY doesn't work. The result is very puzzling because it doesn't even create the convex hull of those points...and the order matters. You can see what it actually does in this JSFiddle.

我最初认为fakepoints是造成这个问题,也许他们在某种程度上,但如果你删除它们这个凸包不适用于组1或2个节点...这是奇怪的,因为我认为我已经添加4点到凸包的输入。一个(可能)的可能性是,我不是以正确的方式添加这四点,但我不知道什么方式,不同于此,是正确的方式。

I first thought the fakepoints were causing the problem, and maybe they are in some way, but if you remove them this the convex hull doesn't work for groups with 1 or 2 nodes...which is weird because I thought I was already adding 4 points to the input of the convex hull. One (likely) possibility is that I am not adding these four points in the right way, but I don't know what way, different from this, is the correct way.

也许有一个很容易的解决方案,有人谁更好地了解D3如何创建凸包。也就是说,也许有人可以看到我的方法有什么问题,并帮助我修复它,或者也许有人已经有一个完全更好的方法来做到这一点。

Maybe there is an easy fix for this for somebody who better understands how D3 is creating the convex hulls. That is, maybe somebody can see what is wrong with my method and help me fix it, or maybe somebody already has a completely better way to do this.

推荐答案

我之前尝试的问题是由使用map函数为 d3.geom.hull 函数内的四个虚拟点引起的。这创建了嵌套的点数组,而不是一个简单的点列表。我找不到一个flatten函数的javascript,所以我把点放在 d3.geom.hull 函数之外使用 forEach() ,并只是这样喂他们:

The problem with my previous attempt was caused by using the map function for the four virtual points inside the d3.geom.hull function. This created nested arrays of points rather than a simple list of points. I couldn't find a "flatten" function for javascript, so I put the points together outside the d3.geom.hull function using forEach() and just fed them in like this:

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个点,使凸包是圆的从各个方向。这样做也不需要添加fakePoints来为具有1或2个成员的组进行帐户。虽然它仍然不像不适应节点大小的正常例子那么好看,如果有必要,美学可以改进你的情况。

As you can see, this works by adding 8 points for every node so that the convex hull is roundish from every direction. Doing so also removes the need to add fakePoints to account for groups with 1 or 2 members. Although it's still not as nice looking as the normal examples which do not adapt to node size, the aesthetics can probably be improved for your case if that's necessary.

这个JSFiddle 有一个工作示例与多个组的组,使每个组的凸包围绕并适应于节点的大小。该可视化仍然需要在其他方面工作(例如重新绘制船体上的边缘,并使链路长度适应组成员资格),但这些是其他问题。这一个是解决,但我仍然可以看到一个更好的答案或这个的改进版本。

This JSFiddle has a working example with multiple layers of groups such that each group's convex hull wraps around and adapts to the size of the nodes. That visualization still needs work on other fronts (such as redrawing the edges over the hulls and making the link lengths adaptive to group membership), but those are other questions. This one is solved, but I'm still open to seeing a better answer or an improved version of this one.

这篇关于如何使一个凸包覆盖D3中不同大小的节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆