D3.js v4/v5 treeを開閉する方法 – サンプル

2018-02-13

D3.jsの階層構造を可視化するtreeの折りたたみ動作についてのプログラムデモです。データの準備とデータ構造については、こちらを、treeの基本的な使い方についてはこちらをご覧ください。

プログラムデモ  (A, C, Hのノードをクリックしてください)

 

サンプルコード

 解説

1. スタイルの準備

始めにノードとリンクのスタイルを設定しておきます。

2. 描画用のデータ準備

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

3. 描画用のデータ変換

準備したデータを、描画用のデータ構造に変更します。hierarchy用のデータに変更した後、先頭のノードを表すrootに初期位置(x0, y0)を設定しておきます。また、tree用のデータ構造に変更する関数(d3.tree)を呼び出し、後のupdate関数内で用います。

4. svg要素の配置

treeを構成する要素を配置する”g”要素だけを設定し、配置はupdate関数内で行います。update関数の詳細は後述します。

 5. クリック時の呼び出し関数

ノードをクリックした際に呼び出す関数を定義します。tree関数は、childrenが定義されているかどうかで末端ノードを判断するため、変数childrenにnullを代入するとそれ以下の構造を切り離すことができます。ノードをもう一度クリックした際に再表示するため、折り畳み時に_children変数を定義してchildrenを退避し、再クリック時に_childrenをchildrenに戻すことで開閉動作を可能にします。

6.svg要素の更新関数

update関数を説明します。関数の手前にあるiは、update関数内でノードデータをsvg要素に設定する際に用います。始めはsourceに先頭の要素(root)が代入されて呼び出されます。(61行目)

まず、tree関数で各ノードの位置を計算します。折りたたみ後も折り畳み前とノードを同じ位置にするため深さ(子、孫)方向の位置を修正します。

ノードデータをsvg要素に設定します。root.descendants()は入れ子になったtreeのノードを配列に変換する関数です。ここで、data()の第二引数として関数

を設定していますが、これはとても重要で、データを割り当てる要素のindexを返り値で設定できるものです。これがないとindexの0から順番にデータが割り当てられるため、折り畳み時に常に配列の最後の要素が折りたたまれる動作となります。初めてupdate関数が呼び出された時はidが設定されていないのでd.id = ++iとして、順番にidを割り振ります。

ノードのenter領域のsvg要素を設定していきます。

始めに”g”要素を設定し、その中に”circle”と”text”要素を設定します。enter領域では、一旦クリックした要素(source)位置にノード位置を設定した後、update領域を含めて所定の位置にノードを移動させます。こうすることで、treeを開くようなアニメーション動作が可能になります。はじめてupdate関数を呼び出した際はすべてのノードが先頭ノード位置に一旦設定されます。また、”g”要素にはclickイベントを設定し、クリックした際にもう一度update関数が呼び出してtreeを更新します。

一旦クリック位置に設定したノードを、更新するtree位置に変更します。enter領域とupdate領域の双方を更新したいので、

として双方をマージします。

はアニメーションを指定する関数で、durationで設定した値の1/1000秒かけて、次のattrで指定した位置に移動します。

次に折り畳み時にノードを消す動作(exit領域)を設定します。

今度はクリックしたノード(source)に徐々に移動するように設定します。”circle”と”text”も徐々に小さく、薄くなるように設定し、消えていくようなアニメーションにします。

リンクも同様に設定していきます。root.links()はtreeのリンクを{source:node, target:node}の形で配列に変換する関数です。リンクのデータ割り当て時も、tree開閉時に整合を取ることを考え、子(target)のidをindexとして指定します。

リンクのsvg要素を設定していきます。

ここで、ポイントはsvg全体の描画領域のgの直後に’path’を挿入し、ノードのsvg要素よりも前に’path’を設定することです。svg要素は後ろに配置されたものが画面の上に描画されるため、’path’よりも’circle’が上に表示され、treeがきれいに描画できます。

また、’path’の”d”に設定している

はtreeで用いる”path”用の水平方向の三次スプライン曲線を算出してくれる関数です。

通常は、155-157行目のように

の形で用いますが、ノードと同様に、一旦クリックしたノード(source)上に座標を配置した後、所定の位置に移動させます。

ノードと同様にリンクのupdate、exit領域を設定します。

最後に、更新した位置を記憶しておきます。これにより、tree開閉時に徐々に移動する動作が可能になります。

まとめ

treeの開閉は少し難しいですが利用シーンの多いモジュールかと思います。少しでも活用していただければ幸いです。