WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

D3.jsによる数値の可視化

今回のエンジニアブログを担当する藤岡です。
宜しくお願い致します。

今回はD3.jsと呼ばれるJavaScriptのライブラリを使い、配列の可視化を行ってみたいと思います。

D3とは「Data-Driven Documents(データ駆動ドキュメント)」の頭文字を取ったもので、その名の通りデータとDOMを結びつける機能があります。
この機能を使うことでデータセットをループ文等で制御する必要が無くなり、コードをシンプルに書くことが可能となっています。

因みに、海外ではD3.jsの人気が高く、現在非常に注目度の高いライブラリです。

D3.jsは、Scriptタグ内に以下の記述をすることで扱えるようになります。

<script charset="utf-8" type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>  

全体の流れ

1, 描画領域を生成(SVG領域)
2, データバインディング
3, 表示の調整

1, 描画領域を生成(SVG領域)

var svg_w = 500; // 幅  
var svg_h = 200; // 高さ  
  
var svg = d3.select("body") // body要素を監視  
            .append("svg")  // svg領域を追加  
            .attr({  
              width: svg_w,  // 幅を設定  
              height: svg_h, // 高さを設定  
            });  

※チェイン構文を使わずともコードは動作しますが、個人的にはチェイン構文を使った方がコードが見やすいように感じます。

e_blog_svg
上記のコードは、bodyタグ内にsvg領域を500 * 200の大きさで生成しています。

js_console_1
JavaScriptコンソールで確認してみるとsvg領域が追加されていることが確認できるかと思います。

2, データバインディング

先ほど用意したSVG領域内に、データセットと対応した棒線を描画します。

var dataset = [10, 20, 30, 40, 50, 60]; // サンプルデータセット  
  
// 棒線を生成  
svg.selectAll("rect")  
   .data(dataset)   // データバインディング  
   .enter()         // データセットを参照し、仮データを生成  
   .append("rect")  // 生成された仮データをSVG領域に追加  
   .attr({  
     x: 0,  
     y: function(d, i) { return i * 40; },  
     width: function(d) { return d; },  
     height: 25,  
     fill: "red",  
   });  
  
// データセット値を文字列としてグラフに表示  
svg.selectAll("text")  
   .data(dataset)  
   .enter()  
   .append("text")  
   .text(function(d) { return d; })  
   .attr({  
     x: 10,  
     y: function(d, i) { return i * 40 + 20; },  
     fill: "black"  
   });  

datasetは配列なのですが、for文等のループ構文が使用されていません。

.data(dataset)  

セレクション対象をrectに設定してから、data()関数でDOMにデータバインドしています。
data()関数はデータセット内の値の個数を数え、解析してくれます。
よって、data()関数がチェインされている全ての要素は、各々のデータセットの個数分繰り返されることになります。

.enter()  

セレクト対象の要素rectはまだ生成されていません。
セレクト対象を生成するにはenter()関数が必要です。
enter()関数は、バインドされたデータを受け取り、DOM要素の個数を比べ、足りない分を仮データとして生成します。

.append("rect")  

enter()関数が生成した仮データを受け取り、svg領域にrect要素を追加しています。

.attr({  
  x: 0,  
  y: function(d, i) { return i * 40; },  
  width: function(d) { return d; },  
  height: 25,  
  fill: "red",  
});  

attr要素の設定に使われている、d, i等の引数はバインドされたデータを監視しています。
これらの動作のお陰で、ループ制御をする必要が無くなっています。

js_console_2
各要素が追加されていることが確認できると思います。

3, 表示の調整

上記のソースは、データセットを棒線グラフの用に表示させています。
graph_1
データの値通りの幅で棒線が表示されていますが、svg描画領域を使い余してしまっています。
このような事態を解消するため、スケールという機能でsvgの表示領域で棒線の幅をリサイズします。

今回ですと、サンプルデータセットの最大値である 60 を svg領域幅の 500 にマッピングすることにより、描画領域を余すこと無く使うことが可能でしょう。

// スケールの定義  
var scale = d3.scale.linear()  
              .domain([0, d3.max(dataset)])  
              .range([0, svg_w])  
              .nice()  
  
// 棒線を生成  
svg.selectAll("rect")  
   .data(dataset)  
   .enter()  
   .append("rect")  
   .attr({  
     x: 0,  
     y: function(d, i) { return i * 40; },  
     width: function(d) { return scale(d); }, // scaleを使用し、幅を設定する  
     height: 25,  
     fill: "red",  
   });  

まずスケールを定義します。
線形を取り扱いますので、linear()関数を使用します。

スケールによるマッピングを行うためには、入力ドメイン(domain())と出力レンジ(range())の設定が必要となります。
※入力ドメイン ... 入力データの取りうる範囲のこと。
※出力レンジ ... 出力値の取りうる範囲のこと。

よって、domainには 0 ~ 60(データセットの最大値) の値を設定し、rangeには 0 ~ 500(svg領域の幅)を設定しています。
後は表示幅をscaleを使って設定してあげるだけです。

graph_2
リサイズされたグラフが表示されました。


いかがでしたでしょうか。
大量のデータセットを扱う際も簡素なコードの記述と、柔軟なデータの可視化が可能です。

公式ドキュメントを見て分かるのですが、D3.jsは奥が深いライブラリです。
その奥深さを理解し、より本格的なグラフの描画に挑戦していきたいです。