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

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

前回の記事では D3.js 3.0 と 4.0 の違いを簡単に記載しました。
今回は、タイマーやグリッドを使ってみようと思います。このまま 4.0 で進めます。

作成するグラフ

WindowsのタスクマネージャーにあるCPU使用率を表すグラフを参考にしてみました。
雰囲気が出ていると思うのですが、いかがでしょう。

See the Pen D3_ Resource_Monitor by book_stone (@book_stone) on CodePen.


ソースコード

主だった個所をメモしたいと思います。

// 0 を100個の配列を作成
var array = d3.range(100).map(function(d) { return 0; });

d3.rangeは、0 から 指定した数までの配列を作成する関数です。
d3.range(10)で、[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]となりますが、
この場合、mapで、値ごとに 0 を返却しているので [ 0, 0, ... , 0, 0] 0が100この配列になります。

// X軸
var tick = d3.range(0 , 100, 10);
var xAxis = d3.axisBottom(xScale)
              .tickSizeInner(-height)
              .tickSizeOuter(-height)
              .tickFormat("")
              .tickValues(tick);

基本的にはスケールを作成して d3.axisBottom(xScale) だけでデフォルト値で動きます。

d3.range(0 , 100, 10) は、0 から 100 まで 10 step という意味で、
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90] を 表します。
tickSizeInner は、グリッドラインの長さです。内側に伸ばすためマイナスになります。
tickSizeOuter は、外側のラインです。これで囲んでいる線を表現します。
tickFormat は、グラフのラベル(数字など)のフォーマットです。今回はなし。
tickValues は、グリッド幅です。range で作った配列を入れています。

// 面の部分
var area = d3.area()
    .x(function(d,i) { return xScale(i); })
    .y0(height)
    .y1(function(d,i) { return yScale(d); });

グラフの薄青い面部分です。
4.0 では、d3.svg.area から d3.area と名称が短くなっています。

area は、データごとに (x0, y0) と (x1, y1) の2点の座標を作成しますが
area.x(value) で x0, x1 同時に設定します。*1
なので、以下と同値(のはず。)

var area = d3.area()
    .x0(function(d,i) { return xScale(i); })
    .y0(height)
    .x1(function(d,i) { return xScale(i); })
    .y1(function(d,i) { return yScale(d); });

当然、データが1個だけだと面にはらない*2ので、データの個数は2個以上で面が表現できます。

詳しくはこちら
GitHub - d3/d3-shape: Graphical primitives for visualization, such as lines and areas.

// カウント
var i = 10

// D3のTimer関数(setIntervalとより良いことがある?)
d3.interval(pushData, 1000 );

これは setInterval と同じような使い方をしています。
次のpushData()を 1000 ms で読んでいます。
カウントも次の呼び出されている関数内で使用しています。

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

  // 正規分布の乱数発生  
  var rand = Math.pow(d3.randomNormal(0, 0.3)(), 2);

  // 配列に追加
  array.push(rand);
  
  // 再描画
  paths.attr("d", line);
  areas.attr("d", area);
  
  // グリッドもずらしていく
  // 呼ばれるごとに 開始するtickの値を 9 はじまり、 8 はじまりと下げている
  tick = d3.range((i--)%10, 100, 10);
  xAxis.tickValues(tick);
  axis.call(xAxis);
  // グリッド線のリセット
  if(i<=0) i=10;
}

1000 ms で呼ばれている関数です。
疑似データとして D3 正規分布ガウス分布*3から取得しています。
d3.randomNormal(0, 0.3)() 平均 0 標準偏差 0.3 の正規分布から取得しています。
二乗しているのはマイナスをなくすためだけです。

tick = d3.range((i--)%10, 100, 10) 

これで、i が 9 に下がると [9, 19, 29, 39, 49, 59, 69, 79, 89, 99] の配列を作成し、
それを新たなX軸のグリッドに入れなおして、動きを表現しています。

感想

とりあえず、動いたといった感じでしょうか。
X軸のグリッドの更新の仕方に不安がありますが。。

ひとまずでした。

*1:正しくは、value が x0 に設定されて、 x1 が null になる。 x1 が null だと x1 は x0 となる。

*2:データが1個で座標が2個、データが2個で座標が2個増えて計4個と・・増えていきます。

*3:通常の乱数でも問題ないと思います。それっぽくデータになるかと思っただけです。