Reputation: 3789
I am trying to build a graph using the force layout in D3. I would like to build different looking nodes depending on the data. Currently all nodes have a category and a name. So I draw an svg:g
consisting of two rect
and two text
elements.
My code currently looks something like this:
// nodes are in the form: { group: 'string', name: 'string2' }
this.node = this.node.data(this.node, function(d) { return d.id; });
var g = this.node.enter().
append('svg:g').
attr('transform', function(d) { return 'translate('+ d.x +','+ d.y +')'; });
g.append('svg:rect').attr('h', 20).attr('w', 100);
g.append('svg:rect').attr('y', 20).attr('h', 20).attr('w', 100);
g.append('svg:text').text(function(d) { d.group; });
g.append('svg:text').attr('y', 20).text(function(d) { d.name; });
If the node doesn't have a name, however, I'd like to supress the creation of the second rect
and text
. Logically, if it wasn't for the implicit iterator in d3 I'd be doing something like:
var g = this.node.enter().
append('svg:g').
attr('transform', function(d) { return 'translate('+ d.x +','+ d.y +')'; });
g.append('svg:rect').attr('h', 20).attr('w', 100);
g.append('svg:text').text(function(d) { d.group; });
// unfortunately 'd' isn't defined out here.
// EDIT: based on comment from the answer below; the conditional should
// be for the text and the related rectangle.
if(d.name) {
g.append('svg:rect').attr('y', 20).attr('h', 20).attr('w', 100);
g.append('svg:text').attr('y', 20).text(function(d) { d.name; });
}
Upvotes: 2
Views: 1084
Reputation: 27544
You could use an each
call on your g
selection to decide whether or not to add the label.
g.each(function(d) {
if (d.name){
var thisGroup = d3.select(this);
thisGroup.append("text")
.text(d.group);
thisGroup.append("text")
.attr("y", 20)
.text(d.name);
});
However, be aware that this structure could get confusing if you're going to be updating the data.
If you want to be able to update neatly, I would recommend doing a nested selection:
var labels = g.selectAll("text")
.data(function(d){ d.name? [d.group, d.name]:[]; });
labels.enter().append("text");
labels.exit().remove();
labels.text(function(d){return d;})
.attr("y", function(d,i){return i*20;});
The data-join function tests the parent's data object, and based on it either passes an array containing the two values you want to use for the label text, or an empty array. If it passes the empty array, then no labels are created; otherwise, each label has it's text set by the value in the array and it's vertical position set by the index.
Upvotes: 6