I have a lot of success creating forceDirect layouts with a single line of text as a label for each node. Now I have a project where I need to add a list (multiple text) to each node.
I have been able to add multiple text to using the same model that works for adding a single label and a single to each node.
The label, rect, and multiline text are each added to separate but only the list of text is not "pinned" to the node.
var node = svg.append("g")
.attr("transform", "translate("+[margin.left, margin.top]+")")
.attr("class", "nodes")
.selectAll("rect")
.data(data.nodes)
.enter()
.append("rect")
.style("width",function(d){
return setRectWidth(d)
})
.style("height",function(d){
return 30
})
.attr("fill",function(d){
return setBackground(d)
})
//.attr("x",0)
.attr("rx",4)
.attr("ry",4)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
var text = svg.append("g")
.attr("class", "text")
.selectAll("txt")
.data(data.nodes)
.enter()
.append("text")
.attr("x", 0)
.text(function(d){
return d.label
})
.style("text-anchor","middle")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
var subtext = svg.append("g")
.attr("class", "subtext")
.selectAll("subtext")
.data(data.node_items)
.enter()
.append("text")
.attr("x", 0)
.text(function(d){
return d.label
})
.style("text-anchor","middle")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
Here is the raw result
Note Subtext has no xy assigned
Here is what I am going for:
The tick function looks ok to me so I don't know what I am missing.
var ticked = function() {
node
.attr("x", function(d) { return d.x + setRectWidth(d)*-.5; })
.attr("y", function(d) { return d.y + setRectHeight(d)*-.5 });
link
.attr("d", function(d) {
var a = []
a.push({x: d.source.x,y:d.source.y});
a.push({x: d.target.x,y:d.target.y});
return line(a)
})
text
.attr("x", function(d) { return d.x })
.attr("y", function(d) { return d.y + setTextY(d) });
subtext
.attr("x", function(d) { return d.x })
.attr("y", function(d) { return d.y });
}
The solution I came up with was to add list times to each node as node items, then use the ticked function to iterate the list and re-assign the x, y positions based on the items index.
You can see the working solution here - https://alqemist.github.io/EAGIR/erd/
Source code is here - look at erd folder https://github.com/alQemist/EAGIR