【Vue.js】Vue.js + Chart.js ドーナツグラフのちょっとした小技【vue-chart.js】

2019.09.06

どうも、むつたくです。
9月です。月日が経つのは早いです。入社してからもう半年経ちました。
その間、色々キャッチアップさせていただきましたし、やれる事の幅は確実に拡がっていると思います。
これからも、どんどん色々なことにチャレンジにしていきます!

 

さて、今回は最近グラフを作成することがあり、Chart.jsを使用しました。
D3.jsの選択肢もあったのですが、シンプルなグラフでしたので、Chart.jsをチョイスしました。
使ってみた所感は、確かに労力少なめで簡単にグラフの描画が出来ました。
ドキュメントも日本語ありで、読むにも問題なく、楽チンでした。

 

では、実際に触ってみましょう。
紹介するのモジュールは、Chart.jsのいくつかあるうちの一つ「Vue-Chartjs」と言われているモジュールです。

 

環境

端末:Mac Book Pro
Vue-CLI:3.9.2
chart.js:2.8.0
vue-chartjs:3.4.2

 

今回やりたいこと

今回はドーナツグラフでの小技と言う事でこのグラフに関する事をやっていきます。
正直、応用でもないですし、他のグラフにもすぐに適用することはできます。

 

  1. 線を無くしたい
  2. 凡例の位置を調整したい
  3. ツールチップの表示内容を変更したい
  4. ツールチップを常に表示したい

 

公式のドキュメントはこちらです。
Vue-Chartjs(GitHub)
Vue-Chartjs(英語ドキュメント)
Chart.js(GitHub)
Chart.js(英語ドキュメント)

 

グラフ作成

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

ひとまず、プロジェクトをVue-CLIで作成してください(Vue-CLI出なくても問題ないですが)。

プロジェクトを作成しましたら、まずは必要なモジュールをインストールします。
インストールするものは「chart.js」および「vue-chartjs」です。

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

注意してください。chart.jsにはjsの前にドットが入りますが、vue-chartjsにはドットがありませんので。

 

⑵componentの作成

Vue-CLIで作成した場合は、src/componentsディレクトリが作成されてますが、その中にグラフ描画のコンポーネントを作成しましょう。

 

(3)ドーナツグラフの作成

ドーナツグラフの場合は、以下のコードになります。ファイル名を「GraphDoughnut.vue」とします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// GraphDoughnut.vue
<script>
// ここでこのコンポーネントで使用するグラフの種類を定義する。今回はドーナツグラフなのでDoughnutとなる。
import { Doughnut } from 'vue-chartjs'

export default ({
  extends: Doughnut,
  data() {
    return {
      datas: {
        // 凡例とツールチップに表示するラベル
        labels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
        // 表示するデータ
        datasets: [
          {
            data: [10, 15, 6, 22, 11, 49, 32],
            backgroundColor: ['#f87979', '#aa4c8f', '#38b48b', '#006e54', '#c1e4e9', '#89c3eb', '#c3d825']
          }
        ]
      },
      options: {
        responsive: true
      }
    }
  },
  mounted() {
    this.renderChart(this.datas, this.options)
  }
})
</script>

これを実行すると、簡単にグラフがcanvasベースに描画されました。
シンプルで簡単ですね!

これをベースに今回やりたい事を追記していきます。

 

ドーナツグラフの小技集

小技① 線を無くしたい

公式ドキュメントの線の説明はここです。
例えば、それぞれのデータの間に空白が出来てる!スッキリ描きたいのに…!白い線が邪魔だ!と言ったときです。
これは簡単に解決できます。線の色を透明ににてしまえば良いのです。

1
2
3
4
5
6
7
8
9
// GraphDoughnut.vue
// ...省略
        datasets: [
          {
            data: [10, 15, 6, 22, 11, 49, 32],
            backgroundColor: ['#f87979', '#aa4c8f', '#38b48b', '#006e54', '#c1e4e9', '#89c3eb', '#c3d825'],
            borderColor: 'transparent' // ★この行追加
          }
        ]

optionsの中に新たにborderColor: ‘transparent’を追加しました。
こうする事で、線が無くなり、各データは隙間なくきっちり表示されました。少しスッキリ。

 

小技② 凡例の位置を調整したい

公式ドキュメントの凡例の説明はここです。
現状では、凡例の位置はデフォルトのtopとなっていますが、この位置を変えたいよとなってくるはずです。
下に、右に、左に配置となってきた場合、これはオプションを追加してあげるだけで可能です。

1
2
3
4
5
6
7
// ...省略
      options: {
        responsive: true,
        legend: {
          position: 'right' // ★この行追加
        }
      }

optionsの中に新たにlegend: { position: ‘right’ }を追加しました。
legend…、自分だけでしょうか、真っ先にHONDAのLEGENDを思い浮かべました。

画像出典:HONDA LEGEND

 

話を戻しまして、このlegendで凡例を細かく設定できます。
potisionで凡例の位置を変更できます。上記例では右側に配置しました。デフォルトは’top’。左に配置したいときは、’left’、下に配置したいときは’bottom’みたいな感じですね。

 

さて、ここで更に問題が発生しました!topとbottomは自動でmiddle-centerの様な感じになってくれますが、rightとleftではtop-centerな感じです。
すっごく気持ち悪いです。Chart.jsのオプションにも無いんですよ、これを指定できるものが…。
なので、自力でゴリゴリ書いていきます。
callback関数で出来るかなと思ったんですが、上手くいかなかったので、プラグインを追加する形でやっていききます。

1
2
3
4
5
6
7
8
9
10
11
// ...省略
mounted() {
  // addPlugin追加
  this.addPlugin({
    afterDraw(chart) {
      const legend = chart.legend
      legend.top = chart.height - (legend.height / 2) - (legend.top / 2)
    }
  })
  this.renderChart(this.datas, this.options)
}

自力でゴリゴリ…とか言っていましたが、これだけです。Chart.jsのプラグイン「afterDraw」を使用して、凡例の位置調整をしています。
凡例がtopやbottomの場合は、消すなり、if文を使って調整してください。
また、あくまでrightやleft時のおおよそのmiddle-centerを実現する方法ですので、若干のズレはあると思います。その際は、各自細かい調整をお願いします。

 

ちなみに上のドーナツの凡例はフォントサイズを大きくしてます。やり方は以下の様になります。

1
2
3
4
5
6
7
8
9
10
11
12
// GraphDoughnut.vue
// ...省略
      options: {
        responsive: true,
        legend: {
          position: 'right',
          // ★ [labels]を追加
          labels : {
            fontSize: 28,
          }
        }
      }

legendの中に新たにlabels: { fontSize: 28 }を追加しました。
まんまです。凡例のラベル情報を変更するのはこのlabelsになっています。他にも様々なオプションがあります。ぜひ公式ドキュメントを読んでみてください。

 

小技③ ツールチップの表示内容を変更したい

それぞれのデータにマウスホバーすると、データが表示されます。デフォルトでは設定したデータが表示されるので、例えばこれをパーセント表示にしたい、とか常に表示しておきたいとかあると思います。
公式ドキュメントのツールチップの説明はここですね。
やり方は以下の様になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// GraphDoughnut.vue
// ...省略
      options: {
        responsive: true,
        legend: {
          position: 'right',
          labels : {
            fontSize: 28,
          }
        },
        // ★[tooltips]を追加
        tooltips: {
         bodyFontSize: 28,
          callbacks: {
            label: function(tooltipItem, data) {
              let total = 0 // 合計格納
              let indexItem = data.datasets[0].data[tooltipItem.index] // マウスを当てたデータ
              // 全データの合計算出
              data.datasets[0].data.forEach(item => {
                total += item
              })
              // パーセント表示
              return Math.round(indexItem / total * 100) + ' %'
            }
          }
        }
      }

今回はcallbacks関数を使用します。callbackではなく、callbacksですから、気を付けてください。
optionsの中に、新たにtooltips: { ……. }を追加しました。
これはツールチップを変更するときに使用するオプションになります。
labelに対して変更を行いたいので、callbacksの中でlabelの関数を定義します。他にもtitleを変更することもできます。
※デフォルトでは、labelの内容しか表示されてません。
第一引数には、「マウスホバーしたデータの情報」が、第二引数には「グラフ全体のデータ」が格納されています。

これでツールチップの表示をパーセント表示に出来ました。これを使えば、自由な表示に出来るので、お試しあれ!

 

小技④ ツールチップを常に表示したい

今度はグラフ中に表示したい場合です。
例えば、常に表示するデータをパーセントで、マウスホバーした時には、データを表示したい…となった場合です。
今回は、プラグインのまたまた登場の「afterDraw」です。
常に表示するデータを各グラフデータの中央に表示したいので、描画後に行います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// GraphDoughnut.vue
// ...省略
  mounted() {
    this.addPlugin({
      afterDraw(chart, go) {
        let ctx = chart.ctx
        chart.data.datasets.forEach((dataset, i) => {
          let dataSum = 0
          dataset.data.forEach((element) => {
            dataSum += element
          })

          let meta = chart.getDatasetMeta(i)
          if (!meta.hidden) {
            meta.data.forEach(function (element, index) {
              // フォントの設定
              let fontSize = 28
              let fontStyle = 'normal'
              let fontFamily = 'Helvetica Neue'
              ctx.fillStyle = '#000'
              // 設定を適用
              ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily)

              // ラベルをパーセント表示に変更
              let labelString = chart.data.labels[index]
              let dataString = (Math.round(dataset.data[index] / dataSum * 100)).toString() + '%'

              // positionの設定
              ctx.textAlign = 'center'
              ctx.textBaseline = 'middle'

              let padding = -2
              let position = element.tooltipPosition()
              // ツールチップに変更内容を表示
              ctx.fillText(labelString, position.x, position.y - (fontSize / 2) - padding) // title
              ctx.fillText(dataString, position.x, position.y + (fontSize / 2) - padding)  // データの百分率

              // 凡例の位置調整
              let legend = chart.legend
              legend.top = chart.height - (legend.height / 2) - (legend.top / 2)
            })
          }
        })
      }
    })
    this.renderChart(this.datas, this.options)
  }
})
</script>

これでツールチップにパーセントで表示され、さらにグラフ上にそれぞれが常に描画されます。

パッと見で理解できるので、これはかなり有効な手段だと思います。
また、title(凡例の情報)と百分率で表示していますが、title部分をデータ値にすれば、マウスホバーの手間が省けて良いかもしれません。
25行目のコードを以下の様に変更してみます。

1
              let labelString = `${chart.data.labels[index]}: ${dataset.data[index]}`


こっちの方が、視覚化的には良いかもしれません。(デザインセンス皆無のむつたくはそう思います。)

 

ちなみに、グラフ中央に何か表示したいとなった場合は、以下の方法で可能です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// GraphDoughnut.vue
// ...省略
  mounted() {
    this.addPlugin({
      afterDraw(chart, go) {
        let ctx = chart.ctx
        chart.data.datasets.forEach((dataset, i) => {
          // ...省略
        })

        // 中央にテキスト表示
        let fontSize = 70;
        let fontStyle = 'normal';
        let fontFamily = "Helvetica Neue";
        ctx.fillStyle = '#000';
        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // position(第二, 第三引数は適宜調整)
        ctx.fillText('スワブロ', chart.width / 2 - 60, chart.height / 2);
      }
    })
    this.renderChart(this.datas, this.options)
  }
})
</script>

 

終わりに

いかがだったでしょうか?
少しコードを追加するだけで、こんな簡単に、しかもわかりやすくなるChart.js。
ノンプログラミングにはなりませんが、JavaScriptの便利なモジュールを紹介しました。
データを視覚化した時はぜひ!

 

 

それでは、また次回に


Top