読者です 読者をやめる 読者になる 読者になる

D3.jsでリソースモニターみたいなグラフの作成

前回、はてなブログで、D3.jsの動作が確認できたので、
表題のようなリソースモニターみたいなグラフができないかと作成してみました。

作成するグラフ

さっそく目標とするグラフを紹介したいと思います。
f:id:stone-book:20161020232329p:plain
データが古いものから左にずれていきますので、リソースモニターっぽく表現しようと思います。

ソースコード

基本的には、D3.jsのサンプルなどを参考にして作成しました。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<style>
/* 軸のスタイル */
.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: auto; /*アンチエイリアス処理*/
}
/* Pathのスタイル */
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
</style>
<body>
  <div id="result">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// マージンの設定(領域)
var margin = {top: 30, right: 20, bottom: 30, left: 50},
    width = 400 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

// 描画データ
var array = [ 2 , 0 , 3  , 4 , -1 , -2 , 5 , -3 , 1 , -5] ;

// スケールの設定 x要素としてインデックス
var xScale = d3.scale.linear()
    .domain(d3.extent(array, function(d,i) { return i; }))
    .range([0, width]);

// スケールの設定 y要素として配列の値
var yScale = d3.scale.linear()
    .domain(d3.extent(array, function(d,i) { return d; }))
    .range([height, 0]);

// X軸
var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .tickFormat(""); // 軸ラベルはなしにした

// Y軸
var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left");

// 線グラフのラインオブジェクト
var linestyle = "linear";
var line = d3.svg.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d,i) { return yScale(d); })
    .interpolate(linestyle);

// SVGの追加
var svg = d3.select("#result").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// グループ要素にX軸を追加
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height / 2 + ")") // 真ん中にした
    .call(xAxis);

// グループ要素にY軸を追加
svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
  .append("text")
    .attr("x", 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .text("Value");

// 実際のラインを追加
var paths = svg.append("path")
    .datum(array) // 配列をマッピング
    .attr("class", "line")
    .attr("d", line);

// データ追加し、再描画がするメソッド
function pushData(){
  // 先頭を削除
  array.shift();

  // +5から-5までの乱数発生
  var rand = Math.floor( Math.random() * 11 ) - 5 ;
  // 配列に追加
  array.push(rand);

  // path要素を削除
  // paths.remove();

  // あらたにPath追加
  line.interpolate(linestyle);

  // 追加して削除だったが、Data-Drivenっぽくない
  // paths = svg.append("path")
  //    .datum(array)
  //    .attr("class", "line")
  //    .attr("d", line);

  // データだけ入れ替る。動きは一緒。
  paths.attr("d", line);

}

// スタイルを変える(コンボのイベント)
function changeStyle(obj){
  linestyle = obj.value;
}
</script>
  </div>
</body>
<input type="button" value="Add" onclick="pushData()"/>
<select name="interpolate" onChange="changeStyle(this)" >
  <option value="linear">linear</option>
  <option value="cardinal">cardinal</option>
  <option value="step-before">step-before</option>
  <option value="step-after">step-after</option>
</select>
</html>

タイマーなどをうまく使うことで、リアルタイムにグラフが更新できるようになりそうです。
これを使ってそれっぽいグラフを次、作成したいと思います。
心電図っぽくして遊ぶのも面白いかもしれませんね。

補足

どうやら、はてなブログ上でうまく動いていなかったようなので、画像に修正しました。
変数名が衝突していたのかな。。
はてなブログ上で、JavaScriptをゴリゴリ動かすより、CodePen利用したほうがいいかもしれませんね。
CodePen - Front End Developer Playground & Code Editor in the Browser

補足2

ソースコードが Data-Drivenっぽくなかったので修正しました。
こちらの記事で動作確認できます。
stone-book.hatenablog.com