问题
I want to know how to make a sankey diagram collapse/expand the nodes based on mouse click.
My diagram is this: https://bl.ocks.org/TheBiro/f73a2a0625bb803179f3905fe7624e22
For example, I want to click on the node "PAGOU" and all of the subsequent links and nodes (on the right) to be removed. I made it based on the Vasco Asturiano (reference on readme.md) aligment options.
回答1:
I adapted the code below from my previous answer here: Collapsible D3 force directed graph with non-tree data
I added properties to the nodes to keep track of whether they are collapsed and how many of their parent nodes are collapsed. Also whether they are collapsible - the source node should not be collapsible because the library doesn't seem to like graphs with no links.
graph.nodes.forEach(function (d, i) {
graph.nodes[i] = { "name": d };
graph.nodes[i].collapsing = 0; // count of collapsed parent nodes
graph.nodes[i].collapsed = false;
graph.nodes[i].collapsible = false;
});
I changed the code for the links to point to the whole source or target node rather than the index because we need the source nodes for filtering. I also set all target nodes are collapsible.
graph.links.forEach(function(e) {
e.source = graph.nodes.filter(function(n) {
return n.name === e.source;
})[0],
e.target = graph.nodes.filter(function(n) {
return n.name === e.target;
})[0];
e.target.collapsible = true;
});
I pulled the layout code out into a function so that we can call it every time a node is clicked. I also added code to filter the graph nodes and links each time based on whether they and their parents are collapsed.
update();
var nodes, links;
function update() {
nodes = graph.nodes.filter(function(d) {
// return nodes with no collapsed parent nodes
return d.collapsing == 0;
});
links = graph.links.filter(function(d) {
// return only links where source and target are visible
return d.source.collapsing == 0 && d.target.collapsing == 0;
});
// Sankey properties
sankey
.nodes(nodes)
.links(links)
.layout(32);
// I need to call the function that renders the sakey, remove and call it again, or the gradient coloring doesn't apply (I don't know why)
sankeyGen();
svg.selectAll("g").remove();
sankey.align("left").layout(32);
sankeyGen();
}
I had to comment out this line because it was interfering with the click handler, I'm not sure what I've changed there.
.on("start", function() {
//this.parentNode.appendChild(this);
})
I added a click handler to perform the collapsing.
node.on('click', click);
function click(d) {
if (d3.event.defaultPrevented) return;
if (d.collapsible) {
// If it was visible, it will become collapsed so we should decrement child nodes count
// If it was collapsed, it will become visible so we should increment child nodes count
var inc = d.collapsed ? -1 : 1;
recurse(d);
function recurse(sourceNode){
//check if link is from this node, and if so, collapse
graph.links.forEach(function(l) {
if (l.source.name === sourceNode.name){
l.target.collapsing += inc;
recurse(l.target);
}
});
}
d.collapsed = !d.collapsed; // toggle state of node
}
update();
}
Complete code in cirofdo's Gist
回答2:
The above fiddle works great for standard trees where each child has a single parent. However, for the multiple parentage ('lattice') scenario where the traditional sankey is uniquely suited; this collapsible representation is perhaps less straightforward. For instance, when expanding node A to show its children, if any A's children have other parents that are not expanded, the parents get expanded automatically. This is probably what you want, since showing only partial parentage would be misleading but it does take you a bit by surprise anyway. Disorientation could be mitigated by not re-centering the nodes. There may be unintended combinatorial expansion effects, especially for highly-latticed data structures.
来源:https://stackoverflow.com/questions/42701752/collapsible-sankey-diagram-d3