How to add node composition to D3 force layout?

I add nodes to the force build graph as follows:

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

Is there a way to add composite SVG elements as nodes? That is, I want to add a hyperlink for each circle, so I need something like this:

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

+7
source share
2 answers

Creating a "composite" element is as simple as adding one or more children to another element. In your example, you want to bind your data to the <a> element and give each <a> one child <circle> .

First of all, you need to select "a.node" instead of "circle.node" . This is because your hyperlinks will be parent elements. If there is no obvious parent element, and you just want to add several elements for each anchor point, use the <g> element, SVG group.

Then you want to add one <a> element to each node in the input selection. This creates your hyperlinks. After setting each hyperlink attribute, you want to give it a child <circle> element. Simple: just call .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(" + dx + "," + dy + ")"; }); 

Remember that D3 primarily works with node selections. Therefore, calling .append() when selecting input means that each node in the selection gets a new child. Powerful stuff!

One more thing: SVG has its own <a> element , as I mentioned above. This is different from HTML! Typically, you only use SVG elements with SVG and HTML with HTML.

Thanks to @mbostock for suggesting that I am specifying a variable name.

+32
source

Answer to Jason Davis (since stackoverflow limits the length of comment comments ...): Great answer. However, be careful with the method chain; usually you want node refer to an external anchor element, not an inner circle element. Therefore, I would recommend a slight variation:

 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(" + dx + "," + dy + ")"; }) .call(force.drag); node.append("circle") .attr("r", 5) .style("fill", function(d) { return fill(d.group); }); 

I also replaced the circle attributes cx and cy with the conversion with the containing anchor element; either one will work. You can consider svg: a elements as svg: g (both are containers), which is nice if you want to add labels later.

+10
source

All Articles