Vue.jsでApexchartsを使ってグラフ描画を行う

# Vue.jsでのグラフ描画ライブラリの選定について
`Apexcharts`, `vue-apexcharts` を使って、Vue.jsで各種グラフの描画をおこなってみます。
当初、`vue-chartjs` を使っていたものの、柔軟性に欠ける、見た目があまり良くない、コードが複雑になりがち等の理由で乗り換えました。

# 描画結果
今回、`折れ線グラフ`、`円グラフ`、`棒グラフ (横型)` の描画を行ってみました。結果は以下。

![linechart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/2029ab7b-e2a7-a6c7-1053-efd426bd7a50.png)
![piechart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/cbc9f2d7-fad9-a4de-42f1-7745bba35d15.png)
![barchart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416295/186c8eaf-9846-4a81-e3b6-967bb91de582.png)

良い点

* 色々なカスタマイズ項目があり、細かい要求に対して融通が利きやすい
* 今回のような単純な例の他、`人口ピラミッド`、`ヒートマップ`、`地図`、`ローソク足`等色々なグラフの描画が可能
* マウスカーソルをグラフ上にあてると特定の結果をハイライト表示できる
* 折れ線グラフはブラウザ上で横軸のズームイン、ズームアウトができる
* 画像としてダウンロード可能
* トランスパイルすればIE11にも対応

参考: [公式のデモ](https://apexcharts.com/vue-chart-demos/)

# インストール

```sh
npm install vue-apexcharts
```

# 折れ線グラフのコードサンプル

サンプルは色々カスタマイズオプションを設定しているため少し長めですが、大部分は省略可能です。

```vuejs
～略～
<!-- 少し色みがかったグラフにするため今回は type="area"にした。通常は type="line" -->
<apexchart
  type="area"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
～略～
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        chart: {
          zoom: {
            type: 'x', // X軸のズームを可能にする
            enabled: true,
            autoScaleYaxis: true,
          },
          toolbar: {
            autoSelected: 'zoom',
          },
        },
        plotOption: {
          line: {
            curve: 'smooth', // 滑らかなラインにする
          },
        },
        xaxis: {
          type: 'datetime', // category, datetime, numericのいずれか。時系列チャートならズームに強いdatetimeがおすすめ
          title: {
            text: '日付',
            offsetY: 10,
          },
          labels: {
            format: 'yy/MM/dd',
          },
          categories: [ // X軸の値
            new Date('2020/03/01 09:00:00'),
            new Date('2020/03/02 09:00:00'),
            new Date('2020/03/03 09:00:00'),
            new Date('2020/03/04 09:00:00'),
          ],
        },
        yaxis: {
          title: {
            text: '回答数',
          },
        },
        title: {
          text: '回答数推移',
          align: 'center',
        },
        tooltip: {
          x: {
            format: 'yy/MM/dd',
          },
        },
        fill: {
          type: 'gradient', // グラデーションをつける
          gradient: {
            type: 'vertical',
            shadeIntensity: 1,
            inverseColors: false,
            opacityFrom: 0.5,
            opacityTo: 0,
            stops: [0, 90, 100],
          },
        },
      },
      series: [
        {
          name: '回答数',
          data: [10, 3, 8, 2], // Y軸の値
        },
      ],
    },
  }),
}
</script>
```

時差が考慮されていないのか、9時間進んだ値を入れないとうまく日本時間に合った表示をしてくれませんでした。(私の調査不足かもしれません)

# 円グラフのコードサンプル

```vuejs
～略～
<apexchart
  type="pie"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
～略～
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        labels: ['20代', '30代', '40代', '50代'],
        title: {
          text: 'あなたの年齢を教えてください。',
          align: 'center',
        },
      },
      series: [5, 8, 3, 2],
    },
  }),
}
</script>
```

# 棒グラフのコードサンプル

```vuejs
～略～
<apexchart
  type="bar"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
～略～
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        plotOptions: {
          bar: {
            horizontal: true, // 横型のグラフにする場合
          },
        },
        title: {
          text: '使用ブラウザー',
          align: 'center',
        },
        xaxis: {
          categories: ['Internet Explorer', 'Google Chrome', 'Firefox', 'Safari'],
        },
      },
      series: [
        {
          name: '件数',
          data: [3, 5, 2, 9],
        },
      ],
    },
  }),
}
</script>
```

# グラフのカスタマイズ

オプション項目の一覧は[APEXCHARTS - Options](https://apexcharts.com/docs/options/)を参照。
ただし、オプションを見ただけではイマイチ具体的な設定方法が分からなかったり、
ところどころVue.jsに合わせて勘でアレンジする必要がありました。
[VUE CHARTS DEMOS](https://apexcharts.com/vue-chart-demos/)にいくつか実コードが載っているケースもあり、参考になりました。

参考: 棒グラフに件数とパーセンテージを両方表示する例

```javascript
options: {
  // ～～略～～
  dataLabels: {
    enabled: true,
    formatter: (val, opt) => {
      return (
        val + '件 (' + Math.round((100 * val) / total) + '%)' // total変数に総件数が入っているものとします
      )
    },
  },
  tooltip: {
    y: {
      formatter: val => {
        return (
          val + '件 (' + Math.round((100 * val) / data.total) + '%)'
        )
      },
    },
  // ～～略～～
},
```

# IE11に対応させる

* promise-polyfill
* classlist.js
* findIndex - timeline/rangebarグラフを使う場合必要
* canvg - PNGでのダウンロードに対応させる場合必要

が必要とのこと。BabelのPolyfillで概ねいけましたが、classlistは別途Polyfillが必要でした。

```sh
npm install classlist-polyfill
```

src/main.js

```javascript
import 'classlist-polyfill'
```

Babelについては他の記事をご参照ください。

# CSSの微調整

Apexchartsのツールバーのz-indexがイケておらず、私の環境ではCSSの調整が必要でした。(場合によると思われます)

```css
.apexcharts-toolbar {
  z-index: 4 !important;
}
```