5

D3 ツリー レイアウトを使用して家系図を作成しようとしていますが、多くの子ノードがある場合、画面全体に水平に広がることに気付きました。理想的には、これらのノードをより垂直にレイアウトして、ユーザーが画面をスクロールする必要がなく、ツリーを見下ろし続けることができるようにしたいと考えています。

これが私が現在見ているものです:

ここに画像の説明を入力

今はそれほど悪くはないかもしれませんが、20 人の子供がいるとしたら、画面全体に広がってしまうので、それは避けたいと思っています。

このような質問を見たことがありますが、単純なサイズ変更ではなく特定のレイアウトが必要なため、これは役に立ちません...大きなノードがあり、ツリーを動的にサイズ変更しようとすると、それらが互いに衝突し始めます-縮小木は私に何の役にも立ちません。特定の数を超える子供がいる状況では、別のレイアウトが特に必要です。

これが私が思い描いていた/望んでいたもののようなものです。ルートには 4 つの子しかないため、この形式は作成されないことに注意してください。理想的には、親に 5 人以上の子がいる場合、以下のレイアウトになるようにしたいと考えています。ルートに 5 つの子がある場合、このレイアウトになり、ユーザーがルートの孫 (A、B、C... ノード) を表示したい場合、レイアウトは単純に縦に引き伸ばされます。必要に応じて、その進行状況の図を取得できます。 ここに画像の説明を入力

カスタムの子レイアウトに関する似たような質問を見つけたのですが、彼は実際の d3js コードをいじる必要があると言いました。私はこれを避けたいので、現在のd3jsでこれが可能かどうかを知りたいと思っています。完全な回答は必要ありませんが、これが可能であることを証明するコードのスニペットは非常に役立ちます。

必要に応じて、人々が遊んでもらえるように JSFiddle をアップロードできます。

4

2 に答える 2

6

このフィドルをチェックしてください:

http://jsfiddle.net/dyXzu/

http://bl.ocks.org/mbostock/4339083からサンプル コードを取得し、いくつかの変更を加えました。この例では、描画時に x と y が入れ替わるため、レイアウトが垂直ツリーとして表示されることに注意してください。

私が行った重要なことは、深度計算機を変更することでした:

オリジナル:

// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });

修理済み:

// Normalize for fixed-depth.
nodes.forEach(function (d) {
    d.y = d.depth * 180;
    if (d.parent != null) {
        d.x =  d.parent.x - (d.parent.children.length-1)*30/2
        + (d.parent.children.indexOf(d))*30;
    }
    // if the node has too many children, go in and fix their positions to two columns.
    if (d.children != null && d.children.length > 4) {
        d.children.forEach(function (d, i) {
            d.y = (d.depth * 180 + i % 2 * 100);
            d.x =  d.parent.x - (d.parent.children.length-1)*30/4
            + (d.parent.children.indexOf(d))*30/2 - i % 2 * 15;
        });
    }
});

基本的に、d3 のデフォルトのノード配置をオーバーライドして、各ノードの位置を手動で計算します。x の自動スケーリングがないことに注意してください。おそらく、最初に開いているノードを調べてカウントし (d.children が存在する場合、d.children は null ではありません。d._children は、ノードが閉じているときにノードを格納します)、次に x の合計を合計することで、これを手動で把握できます。

2 列のレイアウトで子を持つノードは少しファンキーに見えますが、線の描画方法を変更すると改善されるはずです。

于 2013-08-09T16:25:46.677 に答える
0

子を動的にカウントし、それに応じて DOM 要素の幅/高さを調整できます。depthd3.tree.nodes() によって提供されるプロパティを使用するか、ツリーを再帰的にたどることによって計算できる、任意のレベルの子の最大数をカウントすることをお勧めします。以前の SO 回答にあったコードを変更すると、次のようなものになる可能性があります。

    var levelWidth = [1];
    var childCount = function (level, n) {
            if (n.children && n.children.length > 0) {
            if (levelWidth.length <= level + 1) levelWidth.push(0);
                 levelWidth[level + 1] += n.children.length;
            n.children.forEach(function (d) {
                childCount(level + 1, d);
            });
        }
    };
    childCount(0, root);
    var newHeight = d3.max(levelWidth) * 40;  
    tree = tree.size([Math.max(newHeight, 660), w]);
        document.getElementById("#divID").setAttribute("height", Math.max(newHeight, 660) + 50);    

またはnodes()メソッドを使用します。

var nodes = tree.nodes(root), arr = [];
for(i = 0; i < nodes.length; i++)
    arr[nodes[i].depth]++;
var max = 0;
for(i = 0; i <nodes.length; i++)
    if(arr[i] > max)
        max = arr[i];
$('#elementOfChoice').css("height", max*40);
var newHeight = max * 40;  
tree = tree.size([Math.max(newHeight, 660), w]);
于 2013-08-07T17:22:51.320 に答える