フォースレイアウト(力学モデル)を使って描画する (SVG使用)

説明

D3.jsでフォースレイアウト(力学モデル)を使って描画するにはd3.layout.force()メソッドを使います。このメソッドではノード(力学点)と関係性(線)を指定します。ノードはnodes()メソッドで、関係性はlinks()メソッドで指定します。このノードと関連性は、あらかじめ配列に用意しておきます。配列内で示されるノードで重要なのは記述してある順番です。というのも次に記述する関係性では、配列での出現順番を使って、どのノードとノードを結ぶか(関連しているか)を指定するからです。
ノードの関係性を示す配列では関連元を示すsource、関係先を示すtargetを指定していきます。{ source : 0, target : 1}と指定した場合、最初のノードと2番目のノードが関係していることになります。このような関係を必要な数だけ記述します。1つのノードから複数のノードへの関係が発生している場合は、その数だけ記述することになります。
次にsize()メソッドで表示(出力)範囲を指定します。サンプルではSVGの幅を指定しています。
linkDistance()を指定するとノード間の距離を指定できます。距離を指定しないと、かなり狭い幅でノードが表示されてしまいます。最後にstart()メソッドを呼び出せば内部的な処理は完了です。
次に関係性を示す線を描画します。これは線を描くline要素を生成し線の太さや色を指定します。この段階では線のX,Y座標は指定しません。次にノードを示す●印を描画します。これは円を描くcircle要素を生成し半径だけを指定しておきます。線と同様に、この段階では円のX,Y座標は指定しません。
線の描画は力学モデルの処理が行われた時に行います。d3.layout.force()によって生成されたオブジェクトは内部での力学計算処理が発生するたびにtickイベントを発生させます。on("tick", 〜)としてイベントを取得し、イベントハンドラ(関数)を呼び出します。この関数内でノード(●)と関係性を示す線を描画します。線はノードとターゲットのx,yプロパティを、ノードはx,yプロパティを、それぞれの属性値に設定します。あとは、自動的にD3.jsがノードや線を描画し処理してくれます。

サンプル [サンプルを実行する] [サンプルをダウンロード]

HTMLソース

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3.js サンプル</title>
<link rel="stylesheet" href="css/main.css">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<h1>D3.jsサンプル</h1>
<div id="myGraph"></div>
<script src="js/sample.js"></script>
</body>
</html>

JavaScriptコード

var list = {
	nodes : [	// ノードリスト
		{ name : "mz-700" },
		{ name : "PC-6001" },
		{ name : "FM-7" }
	],
	links : [	// ノードとノードを結ぶ線の関係。配列要素の順番をID・参照番号として利用している
		{ source : 0, target : 1 },
		{ source : 0, target : 2 },
		{ source : 1, target : 2 }
	]
};
var svgWidth = 320;	// SVG領域の横幅
var svgHeight = 240;	// SVG領域の縦幅
var svg = d3.select("#myGraph").append("svg")
	.attr("width", svgWidth).attr("height", svgHeight)
// Force Layoutを設定
var force = d3.layout.force()
	.nodes(list.nodes)	// ノードを指定
	.links(list.links)	// ノードとノードを結ぶリンク線を指定
	.size([svgWidth, svgHeight])
	.linkDistance(160)
	.start();
// ノードとノードを結ぶ線を描画
var link = svg.selectAll("line")
	.data(list.links)
	.enter()
	.append("line")
	.style("stroke", "red")
	.style("stroke-width", 5);
// ノードを示す円(●)を描画
var node = svg.selectAll("circle")	// 円を生成
	.data(list.nodes)
	.enter()
	.append("circle")	// circleを追加
	.attr("r", 10)	// 半径は10
// 再描画時に線を描画
force.on("tick", function() {
	link
	.attr("x1", function(d) { return d.source.x; })	// ソースとターゲットの要素座標を指定していく
	.attr("y1", function(d) { return d.source.y; })
	.attr("x2", function(d) { return d.target.x; })
	.attr("y2", function(d) { return d.target.y; });
	node
	.attr("cx", function(d) { return d.x; })	// ノードの座標を指定していく
	.attr("cy", function(d) { return d.y; });
});