ここでは d3 の初心者なので、意味をなさない/非常にばかげている場合は、事前に謝罪してください。
現在、折りたたみ可能なクラスター レイアウトの系統樹があり、複数の親の問題を解決しようとしています。画像を投稿するのに十分なポイントがありません。
スクリーングラブでは、左側の孤立したノード (Moustached Grass Warbler など) が、ノードが接続されていない右側のリンクから移動しました。これらのリンクを再描画し、孤立したノードを 2 番目の親 (15601、15602 など) に接続したいと思います。現在、ノードは新しい位置に移動しますが、どちらのリンクも描画されません。
その後、階層レイアウトが複数の親を持つノードで機能することを意図していないことを発見しましたが、その理由を理解するのに十分なほど d3 をまだ理解していません。これを回避する方法はありますか?私はクラスター レイアウトがデータを視覚化する方法にかなり執着するようになったので、ここで説明されている強制レイアウトでやり直すのではなく、それを維持したいと思います。
それで、私の質問: d3.cluster で 1 つのノードに 2 つの親リンクを描画できますか? それは本当にそうあるべきだと思われます。もしそうなら、どのように?
そうでない場合は、クラスタ レイアウトを強制的に複製する方法についてのリソースをさらに提供していただければ幸いです。
更新機能は次のとおりです。コードのさらに多くの部分が必要な場合はお知らせください。
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root);
links = tree.links(nodes);
nodes.forEach(function(d) {
add_parents(d);
});
// Normalize for fixed-depth.
nodes.forEach(function(d) {
if (d.child_count === 0) {
d.y = h - 150
} else {
//do nothing
}
});
// Update the nodes…
var node = svg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
//this APPEARS to just cause it to update twice for no reason
.on("click", function(d) { toggle(d); update(root); });
nodeEnter.append("circle")
.attr("r", node_size)
.style("fill", function(d) { return (d.child_count > 0 && d._children) ? "#66cccc" : "#fff"; });
//switch out commented stuff in here for vertical vs horizontal tree
nodeEnter.append("text")
//.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
//.attr("dy", ".35em")
//.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.attr("dy", ".5em")
.attr("dx", function(d) { return ( (node_size(d)/16 + (d.name.length/4) + 1) + "em"); })
.attr("text-anchor", "middle")
.attr("transform", "rotate(45)")
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
nodeUpdate.select("circle")
.attr("r", node_size)
.style("fill", function(d) { return (d.child_count > 0 && d._children) ? "#66cccc" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links…
var link = svg.selectAll("path.link")
//this one prevents new link from being drawn to moved node, but links enter from the right place
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.style("stroke-opacity", link_opacity)
//.style("stroke-width", link_width)
.style("stroke", link_color)
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
} // function update()