2012-02-09 117 views
7

我将节点添加到这样的力布局图:如何在D3强制布局中添加复合节点?

var node = vis.selectAll("circle.node") 
    .data(nodes) 
    .enter() 
    .append("circle") 
    .attr("class", "node") 
    .attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }) 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 
    .call(force.drag); 

有没有一种方法来添加复合SVG元素节点?即我想添加一个超链接的每个圆圈,所以我需要的东西是这样的:

<a href="whatever.com"><circle ...></circle></a>

回答

32

创建一个“复合”元素作为附加的一个或更多的孩子到另一个元件一样简单。在你的例子中,你想要将你的数据绑定到一个<a>元素的选择,并给每个一个单一的<circle>孩子。

首先,您需要选择"a.node"而不是"circle.node"。这是因为你的超链接将成为父元素。如果没有明显的父元素,并且您只想为每个数据添加多个元素,请使用SVG的组元素<g>

然后,您要为输入选择中的每个节点附加一个<a>元素。这会创建您的超链接。设置好每个超链接的属性后,您想给它一个<circle>孩子。简单:只需拨打.append("circle")即可。

var node = vis.selectAll("a.node") 
    .data(nodes); 

// The entering selection: create the new <a> elements here. 
// These elements are automatically part of the update selection in "node". 
var nodeEnter = node.enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .call(force.drag); 

// Appends a new <circle> element to each element in nodeEnter. 
nodeEnter.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

记住D3上选择节点主要工作。因此,在输入选择时调用.append()意味着选择中的每个节点都会获得一个新子。强大的东西!

还有一件事:SVG有its own <a> element,这就是我上面提到的。这不同于HTML!通常,您只能将SVG元素与SVG一起使用,并将HTML与HTML一起使用。

感谢@mbostock建议我澄清变量命名。

+0

尽管我明白为什么这是为创作工作,它不更新打破?由于append()合并了输入和更新选项,因此每次更新被调用时都不会为旧节点追加一个新的圆圈? – 2014-08-27 22:53:56

+0

我已更新示例以使其更清晰。 selection.append不会合并任何选择,但selection.enter()。append会自动将元素添加到更新选择中。我最初的例子有vis.selectAll(...).data(...).enter()。append(...)。这只会将元素添加到输入的选择中,所以在那里没有问题;关键在于输入选择最初只包含尚不存在的* new *元素的占位符。 – 2014-08-29 00:18:32

10

回复Jason Davies(因为stackoverflow限制了回复评论的长度...):优秀的答案。尽管如此,请注意链接方法。通常您希望node指向外部锚元素而不是内部圆元素。所以,我建议一个小的变化:

var node = vis.selectAll("a.node") 
    .data(nodes) 
    .enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 
    .call(force.drag); 

node.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }); 

我也换成了圆形的Cx和Cy与含锚元素上的转换属性;任何一个都会工作。你可以将svg:a元素作为svg:g(都是容器),如果你想稍后添加标签,这很好。

+0

谢谢!我稍微修改了第一个示例(删除了'var node =',因为它是多余的,并且可能会在您指出时感到困惑)。变量的第二个例子与你的一致,但我同意这个变换可能更有用。 – 2012-02-16 16:12:45

相关问题