laravel
vue.js
chart.js

Laravel上でVue.jsとChart.jsを利用してグラフを描いてみる

はじめに

もう一度、自分なりに最初っからvueの環境を構築する手順をまとめてみようと思いました。
ついでにchart.jsの導入と動くサンプルを乗っけてます。
素のchart.jsを触ったことはありましたが、コンポーネント化することでいろいろと使い勝手が上がりそうな予感。
Laravelプロジェクトとして作成したけど、ぶっちゃけLaravel要素ほぼないですよね...まあ今後なにか使うときのベースになればなって感じです。

動くやつ

面倒が嫌いな人のために先に GitHub を乗っけておきます。
今回はプロジェクト内にHomesteadをインストールしているため、簡単にう、動きますよ。

動かすまでの手順

先にHomesteadとかcomposerとか、node.jsとかの環境は整っていることとします。

console
git clone https://github.com/tosite0345/vue-chartjs-sample.git

# PHP側パッケージファイルのインストール
composer install

# VM作成
vendor/bin/homestead make

# js側パッケージファイルのインストール
npm install
# 場合によってはこっち
# npm install --no-bin-links
# それでもうまくいかない場合は「導入までの完全な手順」からキャッシュ消去を試す

vagrant up

ちなみにnpm installをローカルマシン側でやってるのは主に処理速度的観点からです。

vagrant起動時にエラーが発生した場合

私の場合、vagrant起動時に次のようなエラーが出ました。

The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

/sbin/ifdown 'eth1' || true
/sbin/ip addr flush dev 'eth1'
# Remove any previous network modifications from the interfaces file
sed -e '/^#VAGRANT-BEGIN/,$ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces.pre
sed -ne '/^#VAGRANT-END/,$ p' /etc/network/interfaces | tac | sed -e '/^#VAGRANT-END/,$ d' | tac > /tmp/vagrant-network-interfaces.post
cat \
  /tmp/vagrant-network-interfaces.pre \
  /tmp/vagrant-network-entry \
  /tmp/vagrant-network-interfaces.post \
  > /etc/network/interfaces
rm -f /tmp/vagrant-network-interfaces.pre
rm -f /tmp/vagrant-network-entry
rm -f /tmp/vagrant-network-interfaces.post

/sbin/ifup 'eth1'

Stdout from the command:



Stderr from the command:

bash: line 5: /sbin/ifdown: No such file or directory
bash: line 19: /sbin/ifup: No such file or directory
console
vagrant ssh
# 以降の作業はVM内で行う
sudo apt-get install ifupdown
exit

# ローカルマシン側で作業
vagrant reload

こちら を参考にさせていただきました。

簡単な説明

ルーティング

こ↑こ↓ をベースにroutes/web.phpを修正しました。
基本的にルーティングはLaravelではなくVue側に丸投げする感じで。
余談ですが恐らくVueルーティングより前にLaravel側のルーティングを記述すれば、例えばログインやランディングページだけはbladeファイルを利用して、その他のアプリケーション部分はVueで処理して、的なことができるはずです。

SPAのテンプレート画面作成

基本的にはresources/views/layouts/app.blade.phpをテンプレートとするが、あくまでも入り口だけ。
内部的なコンポーネントは全てVue側で捌く。

Vue側

resources
+--assets
   +--js
   |   `--*chart                # Chart Templates
   |      +--*DoughnutChart.js
   |      `--*LineChart.js
   +--components                # Vue components
   |  +--*SampleChart.vue
   |  `--*Chart.vue
   +--*app.js
   +--*bootstrap.js             # 起動時の設定とか諸々?
   `--*routes.js                # 今回作成。ルートを記述

*つけてるのが変更したファイルです。

Sample-1

2018-05-08_17h02_09.png

まずは簡単な構成から。
chart.jsでできることを無理やりvue-chartjsにさせてる感あるけどお茶を濁しておきます。
基本的なチャートを描く場合、他のVueファイルと違ってtemplateの記述が不要とのこと。ここで躓きました。
また、chart.jsであればcanvasを用意してそこにデータを流し込んで...って手続きが必要だったのが、それも必要ないとのこと。
最終的にはグラフテンプレートを作って後からAPIやら何やらでデータを流し込む、って形になります。

resources/assets/js/components/SampleChart.vue
<script>
// ここでチャートの種類を選択して...
import { Bar } from 'vue-chartjs'
/**
 * Bar       : 棒グラフ
 * Line      : 折れ線グラフ
 * Doughnut  : ドーナツグラフ
 * Pie       : 円グラフ
 * Radar     : レーダーグラフ
 * Polararea : 極域グラフ
 * Bubble    : バブルグラフ
 * Scatter   : 散布図(mixinでは未対応とのこと)
 **/
export default {
  extends: Bar,
  mounted () {
    // データを流し込むだけ
    this.renderChart({
      labels: ['data-1','data-2','data-3'],
      datasets: [{
        label: 'sample',
        backgroundColor: ['#ddd', '#bbb', "#999S"],
        data: [300, 400, 150],
      }]
    })
  }
}
</script>

ちなみにデータセットについては 公式 のほうが詳しいのでそちらをご参照ください。

Sample-2

2018-05-08_17h38_27.gif

いよいよここからVueの恩恵を感じていきます。
まずはresources/assets/js/chart内にチャートのテンプレートを作成します。
ここはjsのみで記述するため、拡張子は.jsで大丈夫です。

その後、resources/assets/js/components/Chart.vueから呼び出してチャートを利用します。

resources/assets/js/components/Chart.vue
<template>
  <div class="small">
    <h1>vue-chartjs</h1>
    <div class="half">
      <!-- :chart-dataでバインディングを行う。多分オプションとかもバインディングできる? -->
      <doughnut-chart :chart-data="doughnutcollection"></doughnut-chart>
    </div>
    <div class="half">
      <line-chart :chart-data="datacollection"></line-chart>
    </div>
    <div>
      <input type="text" v-model="lines">
      <button @click="fillData()">Repaint</button>
      <button @click="randomize()">Randomize</button>
    </div>
  </div>
</template>

<script>
import LineChart from   '../chart/LineChart.js'
import DoughnutChart from '../chart/DoughnutChart.js'

export default {
  components: {
    // ここで読んだコンポーネントをケバブケースにしたら普通に使えるっぽい
    LineChart,     /* <line-chart></line-chart> */
    DoughnutChart, /* <doughnut-chart></doughnut-chart> */

  },
  data () {
    return {
      datacollection: null,
      doughnutcollection: null,
      lines: 3,
    }
  },
  mounted () {
    this.fillData()
  },
  methods: {
    /**
     * 入力されたデータの数に応じてランダムなチャートデータを作成する
     */
    fillData () {
      var datasets = []
      var dDatasets = []
      var labels = []
      var val = 0
      var dLabels = []
      var dColors = []
      var min = 0
      var max = 0
      var loopCnt = this.lines
      for (var i = 0; i < loopCnt;i++) {
        labels = [this.getRandomInt(), this.getRandomInt()]

        if (max < labels[0]) {
          max = labels[0]
        }
        if (max < labels[1]) {
          max = labels[1]
        }

        datasets.push({
          label: 'data-' + (i + 1),
          backgroundColor: 'rgba(255,100,100,0.1)',
          data: labels,
        })

        dLabels.push('data-' + (i + 1))
        dDatasets.push(this.getRandomInt())
        var code = i * 20
        dColors.push('rgba(255,'+code+','+code+',0.4)')
      }
      this.datacollection = {
        labels: [min, max],
        datasets: datasets
      }
      this.doughnutcollection = {
        labels: dLabels,
        datasets: [
        {
          data: dDatasets,
          backgroundColor: dColors
        }
        ]
      }
    },
    /**
     * 1~10の間で適当にグラフデータ数を設定する
     */
    randomize () {
      this.lines = Math.floor(Math.random() * 10) + 1;
      this.fillData();
    },
    getRandomInt () {
      return Math.floor(Math.random() * (50 - 5 + 1)) + 5
    }
  }
}
</script>

<style>
.small {
  margin:  100px auto;
}
.half {
  width: 45%;
  display: inline-block;
}
</style>

ここ辺りで力尽きましたが、こんな感じでリアクティブにチャートを描画できる素晴らしさが伝わったんじゃないかと思います。

備忘録:環境構築までの完全な手順

console
composer create-project laravel/laravel chart "5.5.*"
cd chart

composer require laravel/homestead --dev
vendor/bin/homestead make
# Mac / Linux
# php vendor/bin/homestead make

npm install
# 環境によっては以下のオプションを付ける必要がある場合もある
# npm install --no-bin-links

# もしうまくいかない場合は次のコマンドを実行する
# フォルダーとキャッシュ消してnpmのバージョン上げてる
# rm -rf node_modules
# npm cache clean --force
# npm install -g npm

# その他パッケージのインストールなど
npm i -g cross-env
npm i vue-cli
npm i chart.js     # 基本的にはvue-chartjsをインストールしたらついてくるはず
npm i vue-chartjs

vagrant up

参考