D3.js packの使い方
D3.jsで階層構造を可視化するpackについて説明する。
サンプルプログラム
サンプルコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 hierarchy pack</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg width="800" height="600"></svg>
<script>
// 1. データを用意
var width = document.querySelector("svg").clientWidth;
var height = document.querySelector("svg").clientHeight;
var data = {
"name": "A",
"children": [
{ "name": "B", "value": 25 },
{
"name": "C",
"children": [
{ "name": "D", "value": 10 },
{ "name": "E", "value": 15 },
{ "name": "F", "value": 10 }
]
},
{ "name": "G", "value": 15 },
{
"name": "H",
"children": [
{ "name": "I", "value": 20 },
{ "name": "J", "value": 10 }
]
},
{ "name": "K", "value": 10 }
]
};
// 2. 描画するデータへ変換
root = d3.hierarchy(data);
root.sum(function (d) { return d.value; });
var pack = d3.pack()
.size([width, height])
.padding(0);
pack(root);
// 3. SVG要素を設定
var node = d3.select("svg").selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("transform", function (d) { return "translate(" + d.x + "," + (d.y) + ")"; });
var color = ["Orange", "Khaki", "Ivory"];
node.append("circle")
.attr("r", function (d) { return d.r; })
.attr("stroke", "black")
.attr("fill", function (d) { return color[d.depth]; });
node.append("text")
.style("text-anchor", function (d) { return d.children ? "end" : "middle"; })
.attr("font-size", "150%")
.text(function (d) { return d.children ? "" : d.data.name; });
</script>
</body>
</html>
サンプルコードの説明
1. データを用意
var data = {
"name": "A",
"children": [
{ "name": "B", "value": 25 },
{
"name": "C",
"children": [
{"name": "D", "value": 10 },
{ "name": "E", "value": 15 },
{ "name": "F", "value": 10 }
]
},
{ "name": "G", "value": 15 },
{
"name": "H",
"children": [
{ "name": "I", "value": 20 },
{ "name": "J", "value": 10 }
]
},
{ "name": "K", "value": 10 }
]
};
描画するデータを用意する。データ構造の詳細はこちらを参照する。また、すべての末端ノードにバブルの大きさを表すvalue値を設定する。親ノードの大きさは、次のデータ変換時に子や孫ノードのvalue値の合計として設定する。
2. 描画するデータへ変換
root = d3.hierarchy(data);
root.sum(function(d) { return d.value; });
var pack = d3.pack()
.size([width, height])
.padding(0);
pack(root);
用意したデータを描画用のデータ構造へ変換する。「用意したデータ -> hierarchy用データ -> 描画種類別データ(ここではpack)」という2段階の変換が必要である。
root = d3.hierarchy(data);
root.sum(function(d) { return d.value; });
上の処理でdataをhierarchy用のデータ構造rootへ変換した後、value値を持たないノードに対して子孫ノードのvalue合計値を計算する。
次に、pack用データへ変換する関数を呼び出す。
var pack = d3.pack()
.size([width, height])
.padding(0);
pack(root);
d3.pack()で呼び出した関数にrootを引数として渡すと、次のようなデータがルートへ付与される。
| 変数 | 説明 |
|---|---|
x |
円の中心x座標。 |
y |
円の中心y座標。 |
r |
円の半径。 |
また、d3.pack()には次の設定が可能である。
pack.radius() |
円の半径を、function(d) { return d.value; }のような関数で指定する。デフォルトは nullである。 |
pack.size() |
packレイアウト全体のサイズを[幅, 高さ]の2要素配列で設定する。引数を指定しない場合は現在のサイズを返す。 デフォルトは [1, 1]である。 |
pack.padding() |
円の接線間の距離を指定する。 デフォルトは0である。 |
3. SVG要素を設定
// 3. SVG要素を設定
var node = d3.select("svg").selectAll(".node")
.data(root.descendants())
.enter()
.append("g")
.attr("transform", function(d) { return "translate(" + d.x + "," + (d.y) + ")"; });
var color = ["orange", "Khaki", "Ivory"];
node.append("circle")
.attr("r", function(d) { return d.r; })
.attr("stroke", "black")
.attr("fill", function(d) { return color[d.depth]; });
node.append("text")
.style("text-anchor", function(d) { return d.children ? "end" : "middle"; })
.attr("font-size", "150%")
.text(function(d) { return d.children ? "" : d.data.name; });
円に対するSVG要素を設定する。最初に"g"要素を設定し、その中に"circle"と"text"を設定する。
データ割り当て部分では次の関数を使用している。
root.descendants()
この関数は、入れ子になったノードを配列として並べる関数である。
"circle"では最初に色配列を設定し、"fill"属性で深さ方向の位置に応じた色を設定している。また、"text"で設定した"text-anchor"は、textの位置を設定するスタイルである。