デモ

いつも通り、完成形のコードはこちらに上げてあります。
ドラッグして遊べるようになってるので、試してみて下さい。

準備

コードはひな形をコピペして、scriptタグの中に書いていって下さい。
まずは、Forceレイアウトで使うデータを準備します。

var dataset = {
    nodes: [
        {id: 0, name: "Taro", sex: "M"},
        {id: 1, name: "Ken", sex: "M"},
        {id: 2, name: "Hana", sex: "F"},
        {id: 3, name: "Mike" ,sex: "M"},
        {id: 4, name: "Bob" ,sex: "M"},
        {id: 5, name: "Anna" ,sex: "F"}
    ],
    links: [
        {source: 0, target: 1},
        {source: 0, target: 3},
        {source: 0, target: 4},
        {source: 1, target: 2},
        {source: 1, target: 5},
        {source: 2, target: 5},
        {source: 3, target: 4},
        {source: 4, target: 5}
    ]
}

友達関係をイメージしたデータです。
nodesは1つ1つの丸(ノード)を表し、linksはノード間の繋がりを表します。

ノードには名前と性別を格納しています。
リンクには誰と誰が友達かという情報が格納されていて、例えば「sourceが0、targetが1ならTaroとKenが友達」という事になります。
分かりやすいようにノードにID番号を付けていますが、実際は順番だけしか見ないので無くても構いません。

その後、svg領域を準備します。この辺はお決まりですね。

var width = 960;
var height = 500;
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

グラフの描画

Forceレイアウトの適用部分は、このようになります。

var force = d3.layout.force()
    .nodes(dataset.nodes)
    .links(dataset.links)
    .charge(-200)
    .linkDistance(200)
    .size([width, height])
    .start();

まずは、D3に用意されているforceメソッドを呼びます。
nodesにはデータセットのノードを、linksにはデータセットのリンクをそれぞれ与えます。

chargeは反発力を表していて、マイナスの値が大きいほどノード同士が離れやすくなります。
linkDistanceは名前の通り、ノード間のリンクの距離です。

sizeは適当に決めてあげて、最後にstartを呼び出せば準備は完了です。
次に、リンクの描画部分を書きます。

var link = svg.selectAll(".link")
    .data(dataset.links)
    .enter()
    .append("line")
    .attr("class", "link");

dataにリンクのデータを与え、lineをappendすれば、あとはD3が勝手に描画してくれます。
簡単ですね!後ほどリンクにCSSを適用させるため、それぞれにlinkクラスを付与しています。

次はノードの描画部分です。

var node = svg.selectAll(".node")
    .data(dataset.nodes)
    .enter()
    .append("circle")
    .attr("class", "node")
    .attr("r", 10)
    .style("fill", function(d) {
        if(d.sex == "M"){
            return "blue";
        }else{
            return "red";
        }
    })
    .call(force.drag);

少し長いですが、中身はさっきのコードとほぼ同じです。
dataにノードのデータを渡しただけで、あとは見た目を整えているだけです。

ノードの色を、性別が男だったら青色、女だったら赤色にしています。
最後のcallでforce.dragを与えると、ドラッグ可能なグラフになります。

tickの追加

サンプルコードを動かすと分かるのですが、グラフは最初くねくね動きます。
そのアニメーションを制御しているのが、このtickの処理です。

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; });
});

tickは1/30秒に一回呼ばれて、ノードとリンクに位置を与えています。
まあ、Forceレイアウトを使う時は、おまじない的に付けておいて下さい。

最後に、以下のCSSを適用します。

.node {
    stroke: #fff;
    stroke-width: 1.5px;
}
.link {
    stroke: #999;
    stroke-opacity: .6;
}

これを実行すると、以下の様なグラフが出来上がります
(グラフの形は実行するたびに変わります)。

pic20140320-1

まとめ

いかがだったでしょうか?
D3のコードは若干長く感じますが、一度書いてみると意外と大したことありません。
これを気に色々なレイアウトを試してみると、楽しいかもですね。

CATEGORIES