[vue] vue-chartjsのreactiveDataを用いてリアクティブにグラフを描画する

概要

グラフ描画ライブラリのJavaScriptライブラリであるChart.jsを、Vueから使いやすくしたラッパーライブラリであるvue-chartjsを用いて、グラフをリアクティブに描画するサンプル。

前提

debian 8.6
node 5.12.0
vue 2.4.1
chart.js 2.7.1
vue-chartjs 3.1
  • webpackを用いた、単一ファイルコンポーネントによるVueの利用を前提とする
  • vue及びchartjsに関する解説は割愛する

目的

以下のGif動画のように、スライダによるデータの変更に応じて、リアクティブに棒グラフを描画する。

グラフ描画用のデータは、下記のようにコンポーネントへのプロパティに、データ本体のみを指定して使えるようにする。

<graph-sample :data1="40" :data2="30"/>

モジュールのインストール

グラフ描画用のchart.jsと、それをVueで利用するvue-chartjsをnpmでインストールする

$ npm install --save vue-chartjs
$ npm install --save chart.js

※ vue-chart.jsだけインストールすればchart.jsへの依存を解決してくれるハズだが、どうにも手元の環境で上手く解決できなかったのでchart.jsも別途入れるように対応した

親コンポーネントの実装

親コンポーネントは、2種類のスライダと、そのスライダの値をプロパティにしたグラフ用コンポーネントを描画する。

なお、本記事ではvue用のUIライブラリであるelement-uiのスライダコンポーネントを用いているが、本記事の本筋とは関係ないため詳細は割愛する。

また、グラフ描画用のコンポーネントは、同ディレクトリのGraphSample.vueに存在するものとする。

<template>
  <div>
    <el-slider v-model="data1" :min="0" :max="100" />
    <el-slider v-model="data2" :min="0" :max="100" />
    <graph-sample
      :data1="data1"
      :data2="data2"
    />
  </div>
</template>
<script>
  export default {
    data: function() {
      return {
        data1: 40,
        data2: 80,
      }
    },
    components: {
      GraphSample: require('./GraphSample')
    }
  }
</script>

グラフ描画用コンポーネントの実装

  • vue-chartjsは、そのコンポーネント自体をグラフコンポーネントにしてくれるので、templateタグを記述する必要はない
  • vue-chartjsから、Barオブジェクトをimportし、それをミックスインすることで棒グラフを利用できる
  • vue-chartjsから、reactiveDataオブジェクトをimportし、それをミックスインすることでdataを監視してリアクティブにグラフを再描画できるようになる
  • reactiveDataをミックスインすると、chartDataというグラフ描画用データが定義され、それを書き換えることでグラフも再描画される
  • mountedで最初にグラフ描画用データのベースを定義する
  • 親コンポーネントから、スライダの変更に応じてプロパティが書き換わるので、それをwatchして、変更をchartDataに反映させる
<script>
  import VueCharts from 'vue-chartjs'
  import {Bar, mixins} from 'vue-chartjs'
  export default {
    mixins: [Bar, mixins.reactiveData],
    data: function() {
      return {
        options: {
          scales: {
            yAxes: [
              {
                ticks: {
                  min: 0,
                  max: 100,
                }
              },
            ]
          },
        },
      }
    },
    props: {
      data1: {
        type: Number,
        required: true,
      },
      data2: {
        type: Number,
        required: true,
      },
    },
    watch: {
      data1: function() {
        this.updateChartData()
      },
      data2: function() {
        this.updateChartData()
      }
    },
    methods: {
      updateChartData() {
        const newChartData = Object.assign({}, this.chartData)
        newChartData.datasets[0].data = [this.data1]
        newChartData.datasets[1].data = [this.data2]
        this.chartData = newChartData
      },
    },
    mounted: function() {
      this.chartData = {
        datasets: [
          {
            label: 'data1',
            data: [this.data1],
          },
          {
            label: 'data2',
            data: [this.data2],
          },
        ],
      }
    }
  }
</script>

デモ(再掲)

備考

  • reactivePropを用いたリアクティブなグラフ描画の方法はググると沢山出てくるのに、reactiveDataを用いたものが余り無かったので、ソースコードを読んで試してみた。

  • reactivePropを用いた場合、プロパティにグラフ描画用データ全体を指定する必要があり、今回の用に棒グラフの値本体のみをプロパティで指定する仕組みにしたい時に使いづらかったので、reactiveDataを使う方法を採用した

  • かなり我流を含んでいる気がする。もっと楽な方法でリアクティブな描画ができるかも。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です