ゆっくり開発

開発したい時に開発するブログ

vue-chartjs で二重Y軸を扱う

各単語について

  • Vue.js
    Javascriptフレームワークの一つ. HTML側とJS側で値の共有ができ(双方向データバインディング), また,HTML側でforやif文が書けるようになる便利なやつ.
  • Chart.js
    JavaScriptで洒落たグラフを簡単に書けるようにするライブラリ.
  • vue-chartjs
    Vue.js上でChart.jsを使うためにChart.jsをラップしたもの.

今回の開発の概要

vue-chartjsの二重Y軸の扱いに結構詰まったので, 今回の対処をメモする.
今回は以下の流れで開発した.

  1. vue-chartjsで同じ描画先に棒グラフを2本描画
  2. Y軸を2本描画し,各グラフで異なるY軸を参照
  3. 各グラフが紐づくY軸を,切り替えるボタンを作成

Y軸を2本描画し,各グラフで異なるY軸を参照

"vue-chartjsで同じ描画先に棒グラフを2本描画"はメモするまでもないので省略.

Y軸を複数描画する際は,グラフ描画関数の引数のoptions要素を編集する. 具体的には,以下の様にyAxes要素を配列にする.

options: {
  scales: {
    yAxes: [{
      id: "y-axis-1",
      position: "left"
    },
    {
      id: "y-axis-2",
      position: "right"
    }]
...

positionの値で描画先の上下左右どこに描画するか定義できる.
また,各グラフでどちらのY軸に紐付かせるかは,上記のidを以下の様にyAxisID要素に格納することで,定義できる.

{
  type: 'bar',
  label: 'label1',
  backgroundColor: '#f87979',
  data: [11, 11, 19, 8, 8, 9, 30, 24, 25, 22, 11, 15],
  fill: false,
  tension: 0,
  yAxisID: 'y-axis-1'
},
{
  type: 'bar',
  label: 'label2',
  backgroundColor: '#f87000',
  data: [5, 25, 17, 6, 29, 5, 5, 13, 16, 10, 14, 29],
  fill: false,
  tension: 0,
  yAxisID: 'y-axis-2'
}

以下の用にY軸が左右に描画される. ピンクの棒グラフが左のY軸,オレンジの棒グラフが右のY軸に紐づいている.

f:id:uttnaoki:20180805003001p:plain

各グラフが紐づくY軸を,切り替えるボタンを作成

ここで詰まった.結局,いいやり方にはなっていないと思うが, 今回は以下の方法で対処した.

  • ボタンクリックにより,yAxisIDの値を変更
  • 修正したグラフのデータの_meta要素を削除し,グラフを再描画

ボタンクリックにより,yAxisIDの値を変更

以下のコードでyAxisIDの値を変更するラジオボタンを設置

<td v-for="col in filteredData.datasets.length">
  <!-- id には (axis_select-列番号-軸番号) を格納 -->
  <input type="radio" :id="['axis_select-' + (col-1) + '-1']" value="y-axis-1"
      v-model="filteredData.datasets[col-1].yAxisID" @input="deleteMeta">
  <label for="y-axis-1">軸1</label>
  <input type="radio" :id="['axis_select-' + (col-1) + '-2']" value="y-axis-2"
      v-model="filteredData.datasets[col-1].yAxisID" @input="deleteMeta">
  <label for="y-axis-2">軸2</label>
</td>

filteredData変数にグラフ描画に使うデータが入っている.
上記コードで設置したボタンをクリックすることにより,deleteMeta()関数を呼び出し,_meta要素を削除する.

修正したグラフのデータの_meta要素を削除し,グラフを再描画

上で設置したラジオボタンのクリックにより発火するdetaMeta()関数は以下の通り.

// データの(_meta)要素を削除し,グラフを更新
deleteMeta (e) {
  // buttonId は axis_select-0-1 の形式
  // ハイフン区切りで,(axis_select 列番号 軸番号) を意味する
  const buttonId = e.target.id;
  const index = Number(buttonId.split('-')[1]);

  delete this.localData.datasets[index]._meta;
  // グラフを更新
  this.reloadGraph();
}

動作テスト

以下は今回開発したものを実際に動かしたものです. 二つ目のグラフ(オレンジの棒)のY軸を 左->右->左 と動かしています. オレンジのグラフの最大値はピンクのグラフの最大値よりも大きいため, ピンクの方のグラフも動いています.

f:id:uttnaoki:20180805005522g:plain

感想

とりあえず,ちゃんと動くものはできたので,目的は達成しました. でも対処の仕方があまりきれいではないので,すっきりしない.

開発には関係ないことですが,今回初めて画面キャプチャで動画を作成し,GIFを作成しました. 楽しい.