D3.js v4/v5 tree 使い方 – サンプル

2018-02-10

D3.jsの階層構造を可視化するtree(d3.hieararchy)のプログラムデモです。マインドマップや関連性の表示に活用できます。データの準備とデータ構造については、こちらをご覧ください。

似た構造にclusterがあります。違いは、末尾のノードを同じ位置に揃えるかです。

プログラムデモ – 描画のみ

 

サンプルコード

 解説

1. スタイルの準備

リンクのスタイルを設定しておきます。今回、ノードのスタイルはsvg要素に直接設定します。

2. 描画用のデータ準備

描画用のデータを用意します。データ構造の詳細はこちらを参照ください。

3. 描画用のデータ変換

準備したデータを、描画用のデータ構造に変更します。準備したデータ→hierarchy用のデータ→描画種類ごと(今回はtree)のデータと2段階の変換が必要です。

まず、

のコマンドで、dataをhierarchy用のデータ構造rootに変更します。rootには、こちらの変数が設定されます。

次に、tree用のデータに変更するための関数を呼び出します。

d3.tree()で呼び出した関数にrootを引数として設定すると、次のデータがrootに付与されます。

x ノードの並び(兄弟)方向の座標
y ノードの深さ(親子)方向の座標(先頭が0)

今回のデモでは、付与される座標はxが画面縦方向、yが画面横方向となりますので注意が必要です。

また、d3.tree()には以下の設定が可能です。

tree.size() 描画する構造のサイズを[並び方向, 深さ方向]の2要素配列で設定します。引数が設定されていない場合は現在のサイズを返します。デフォルトは[1, 1]。
tree.nodeSize() ノード1つのサイズを[並び方向, 深さ方向]の2要素配列で設定します。引数が設定されていない場合は現在のサイズを返します。デフォルトはnullです。nodeSize()がnullの場合は上のsize()を使用します。nodeSize()が指定されている場合先頭の要素の位置が(0,0)に設定されます。
tree.separation() 隣り合う要素間の間隔を決める関数を設定します。デフォルトは次の関数になっています。
function separation(a, b) {
return a.parent == b.parent ? 1 : 2;
}
本プログラムデモはデフォルト設定で、隣り合うノードが異なる親の場合、同じ親の場合と比較して2倍の隙間が空いています。

ここで、今回はsize( )を使ってtreeの幅を設定していますが、先頭の座標が0、深さ方向末端の座標が設定した幅となるように計算されるため、

のように、svgの描画領域の幅より小さめにtreeの幅を設定しています。

4. svg要素の配置

先頭の要素の座標が0に設定されるため、グループを表す”g”要素を設定して全体をx方向に移動させます。このグループ要素の中にノードとリンクを設定していきます。

まず、リンク用のsvg要素を設定します。

データの割り当ての部分で

の関数を使っていますが、これは入れ子になったノードを配列として並べてくれる関数です。順番は指定したノードに対する深さ方向、並び方向の順で並びます。今回のデモでは、A→B→C→G→H→K→D→E→F→I→Jの順です。また、子から先頭に向かってリンクを描画する設定で、先頭Aからのリンクはないためsliceで先頭のノードを除外しています。

続いてノードのsvg要素を設定します。

ノードには’circle’と’text’の二つを設定するため、はじめに’g’要素を設定し、その中に’circle’と’text’を設定していきます。’g’要素で位置を設定していますが、treeの深さ方向がy、並び方向がxである点に注意してください。

子ノードが多くあるノードの右側はリンクが密集するため、子ノードがある場合は右側、無い場合は左側にtextを設定しています。”text-anchor”はtextの位置を設定するスタイルです。

まとめ

データを2回変換する必要があることと、y座標がtreeの深さ方向である点が分かりにくい点です。ご注意ください。冒頭にも述べましたがclusterとtreeは関数を一つ変えるだけです。相互の変換が可能です。また、treeの応用編としてノードをクリックしたときに子ノードを折りたたむ方法をまとめています。