47
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VueAdvent Calendar 2019

Day 5

Vueでグラフ描画するなら、Google Chartがオススメ

Last updated at Posted at 2019-12-04

はじめに

これはVue Advent Calendar 2019 5日目の記事です。

最近、Vue.jsで集計結果をグラフ描画する機会がありました。
Vue グラフ描画で調べると基本的にCharts.jsが出てきます。
色々、考えt時に、Google chartsが便利だったので紹介したいと思います。

google chartsとは

google chartsとは、googleの図表描画ライブラリです。
スプレッドシートとかで使われているグラフを描画できるイメージです。

プロジェクト作成

  • 素のVue.jsではなく、Nuxt.jsでやっていたためNuxtでプロジェクト作成
yarn create nuxt-app charts-sample
# yarnを選択
# cssフレームワークはbulmaを選択
cd charts-sample
yarn dev

インストール

Google chartsのVue向けWrapperのvue-google-chartsです。

yarn add vue-google-charts
  • iconを読みこませたいので、google iconを追加
nuxt.config.js
省略
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      // 下記を追加
      { href: 'https://fonts.googleapis.com/icon?family=Material+Icons', rel: 'stylesheet' }
    ]

グラフコンポーネント

  • グラフの種類とデータ、オプションを渡してあげると描画してくれるようにしています。
piechart.png
components/atoms/Chart.vue
<template>
  <GChart
    :type="chartType"
    :data="chartData"
    :options="chartOptions"
    :createChart="
      (el, google, type) => {
        return new google.visualization[type](el)
      }
    "
  />
</template>

<script>
import { GChart } from 'vue-google-charts'

export default {
  components: {
    GChart
  },
  props: {
    chartType: {
      type: String,
      default: ''
    },
    chartData: {
      type: Array,
      default: () => {
        return []
      }
    },
    chartOptions: {
      type: Object,
      default: () => {
        return {}
      }
    }
  }
}
</script>
pages/index.vue
<template>
  <div class="container">
    <chart
      :chartType="chartType"
      :chartData="chartData"
      :chartOptions="chartOptions"
    />
  </div>
</template>

<script>
import Chart from '@/components/atoms/Chart.vue'

export default {
  components: {
    Chart,
    Dropdown
  },
  data() {
    return {
      chartType: 'PieChart',
      chartData: [
        ['', '売上', '費用', '収益'],
        ['2014', 1000, 400, 200],
        ['2015', 1170, 460, 250],
        ['2016', 660, 1120, 300],
        ['2017', 1030, 540, 350]
      ],
      chartOptions: {
        title: '会社の損益',
        subtitle: '売上',
        width: 500,
        height: 500
      }
    }
  }
}
</script>

100%積み上げ棒グラフを描画

100barchart.png
  • chartOptionにisStacked: 'percent'を追加する

      chartOptions: {
        title: '会社の損益',
        subtitle: '売上',
        width: 500,
        height: 500,
        isStacked: 'percent'
      }

アノテーションを付ける

  • グラフを描画していると、グラフに数値を表示したくなります。
100barchartannotation.png
components/atoms/ChartWithAnnotation.vue
<template>
  <GChart
    :type="chartType"
    :data="data"
    :options="chartOptions"
    :createChart="
      (el, google, type) => {
        return new google.visualization[type](el)
      }
    "
    @ready="onChartReady"
  />
</template>

<script>
import { GChart } from 'vue-google-charts'

export default {
  components: {
    GChart
  },
  props: {
    chartType: {
      type: String,
      default: ''
    },
    chartData: {
      type: Array,
      default: () => {
        return []
      }
    },
    chartOptions: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data() {
    return {
      viewOption: {
        calc: 'stringify',
        type: 'string',
        role: 'annotation'
      },
      data: null
    }
  },
  methods: {
    onChartReady(chart, google) {
      console.log('annotation')
      this.addValueLabel(chart, google)
    },
    addValueLabel(chart, google) {
      const dataArr = this.chartData
      const data = google.visualization.arrayToDataTable(dataArr)

      const formatPercent = new google.visualization.NumberFormat({
        pattern: '#,##0.0%'
      })

      const view = new google.visualization.DataView(data)
      const viewColumn = []
      const sumObj = this.calcTotal(dataArr)
      dataArr[0].forEach((val, i) => {
        viewColumn.push(i)
        if (i !== 0) {
          const viewOption = JSON.parse(JSON.stringify(this.viewOption))
          viewOption.sourceColumn = i

          viewOption.calc = (dt, row) => {
            const amount = dt.getValue(row, i) / sumObj[row]
            return formatPercent.formatValue(amount)
          }
          viewColumn.push(viewOption)
        }
      })
      view.setColumns(viewColumn)
      chart.draw(view, this.chartOptions)
    },
    calcTotal(dataArr) {
      const sumObj = {}
      dataArr.forEach((arr, i) => {
        // 1行目はヘッダーなので飛ばす
        if (i !== 0) {
          sumObj[i - 1] = 0
          arr.forEach((val, j) => {
            // 2行目以降の1カラム目はタイトルなので飛ばす
            if (j !== 0) {
              sumObj[i - 1] += Number(val)
            }
          })
        }
      })
      return sumObj
    }
  }
}
</script>
  • アノテーションのフォーマットは、下記のように指定しています。
  • パターンを変えれば数値やパーセント表示以外でも表示することが可能です。
      const formatPercent = new google.visualization.NumberFormat({
        pattern: '#,##0.0%'
      })

最後に

  • google-chartsの紹介でした。

google chartsの良いところ

  • グラフが豊富
  • データ構造が同じで複数のグラフを描画できる
  • アノテーションなど拡張性が高い(別途拡張用のライブラリとか不要)

主観ですがデザインはデフォルトだと少しダサいなと感じますw

昨今、データの分析結果、集計結果の可視化がトレンドなので、vue × google chartで簡単にグラフ描画が可能なので、触ってみてください。
今回のソースコードは、ここにあがってます。

明日は@daikidsさんです。

47
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?