Reputation: 33
Hi stackoverflow community,
i'm looking for a solution to place nodes inside bigger ones with d3 because i need to show that some parts of the graph happen in a specific area.
The input is a JSON object and looks like this:
{
"nodes": [
{"id": "sourcSink1", "label": "sourcSink1", "compartment": null},
{"id": "process1", "label": "process1", "compartment": null},
{"id": "element1", "label": "element1", "compartment": "compartment1"},
{"id": "compartment1", "label":"compartment1", "compartment": null},
]
"edges": [
{"source": "sourcSink1", "target": "process1", "class": 1},
{"source": "process1", "target": "element1", "class": 2},
]
}
The node "compartment1" should contain "element1". Is there a possibility to accomplish this with d3.js?
I'm thankfull for every hint :)
Upvotes: 2
Views: 352
Reputation: 10642
Here is a quick example of what could be done : https://jsfiddle.net/thatOneGuy/qhL8wztm/1/
First off adjust the radius. I have put a check in to see if the node has children :
node.each(function(d) {
if (d.compartment) {
node.filter(function(e) {
if (e.name == d.compartment) {
e.hasChildren = true;
}
})
}
})
Then adjusted the radius. If it has children make it 20 else 5 :
node.attr("r", function(d) {
if (d.hasChildren) {
return 20;
} else {
return 5;
}
})
Now to adjust the coordinates. So on tick if the node has a compartment it moves to the node with a name that matches that compartment and sets d.x and d.y accordingly:
node.attr("cx", function(d) {
if (d.compartment) {
node.filter(function(e) {
return e.name == d.compartment;
}).each(function(e) {
d.x = e.x
})
}
return d.x;
})
.attr("cy", function(d) {
if (d.compartment) {
node.filter(function(e) {
return e.name == d.compartment;
}).each(function(e) {
d.y = e.y
})
}
return d.y;
});
This isn't perfect, but it works. Obviously it need a bit of playing with, for example, bringing the children in front of the container node etc. But you can get the basics from this :)
EDIT
I have also added a class. If the node has to be in a container, set pointerEvents to none. This is so it doesn't effect the dragging :
.attr("class", function(d){
if(d.compartment){
return "node noPointers"
} else {
return "node"
}
})
CSS :
.noPointers{
pointer-events:none;
}
Updated fiddle : https://jsfiddle.net/thatOneGuy/qhL8wztm/3/
Upvotes: 3