Vue.js × Firestore × Chart.js を使いリアルタイムでグラフを更新する方法

26833 ワード

Cloud Firestore でリアルタイムアップデートを使うとデータ登録された時点で画面の値を更新することができます。

Chart.js を使い値をグラフ化する場合でも同様に更新可能です。

今回はそのやり方について書きたいと思います。

事前準備

Firestore

Firebase にアクセスしてアプリの登録と Database の作成を行います。

Chart.js と vue-chartjs をインストール

npm または yarn でインストールできます。公式サイト の通りすると Chart.js の3系がインストールされうまく動作しませんでした。バージョンを2で指定する必要があります。(2021年7月時点)

データの取得

ストアでデータ取得する際に onSnapshot を使うことでデータの変更があれば画面を更新するようにできます。

actions: {
  fetchQuestions({ commit }) {
    firebase.firestore().collection('question').onSnapshot(snapshot => {
	// Firestore のデータを取得してステートに入れて使う
    });
  },

データの更新

コンポーネントにフォームとメソッドを作成します。

<label>
  <input type="radio" :value="'yes_' + item.id" v-model="answer[index]">Yes
</label>
<label>
  <input type="radio" :value="'no_' + item.id" v-model="answer[index]">No
</label>

<input type="submit" value="送信" @click="send">

methods: {
	send() {
		this.$store.dispatch('addAnswer', this.answer);
	}

ストアに登録処理です。

import firebase from "firebase/app";

mutations: {
	addAnswer() {
    router.push({ name: 'done' }, () => {});
  },

actions: {
	addAnswer({ commit }, answer) {
		// Firestore のデータを更新
  },

ラジオボタンを選んで送信ボタンを押すとデータが登録されるはずです。画面はこんな感じ。

グラフの描画

Chart.vue というコンポーネントを作ってその中でグラフを作成し Result.vue で読み込みます。

初回は mounted からグラフの作成を開始し、回答が送信されデータが変わると questions の値が更新されグラフの再作成が行われる仕組みです。

<script>
import { mapActions } from 'vuex';
import { Bar } from 'vue-chartjs';

export default {
  extends: Bar,
  watch: {
    questions: {
      handler() {
        this.makeChart();
      },
      deep: true
    }
  },
  mounted() {
    if (this.$store.state.questions.length === 0) this.fetchQuestions();
    this.makeChart();
  },
  data() {
    return {
      chartData: {
        contents: [],
        labels: null,
        datasets: [
          {
            label: 'Yes',
            data: null,
            borderWidth: 1,
            backgroundColor: '#ccffff'
          },
          {
            label: 'No',
            data: null,
            borderWidth: 1,
            backgroundColor: '#ffcccc'
          }
        ]
      },
      options: {
        scales: {
          xAxes: [{
            scaleLabel: {
              display: true,
              labelString: ''
            }
          }],
          yAxes: [{
            ticks: {
              beginAtZero: true,
              stepSize: 10,
            }
          }]
        }
      },
      questions: this.$store.state.questions,
    }
  },
  methods: {
    makeChart() {
      this.chartData.labels = [];
      let yes = [], no = [];
      this.$store.getters.getAnswers.forEach((answer, index) => {
        this.chartData.labels.push('No ' + (index + 1));
        yes.push(answer.yes);
        no.push(answer.no);
      });
      this.chartData.datasets[0].data = yes;
      this.chartData.datasets[1].data = no;

      this.renderChart(this.chartData, this.options);
    },
    ...mapActions(['fetchQuestions'])
  }
}
</script>
<template>
  <div class="contain">
    <h3>アンケート回答結果</h3>
    <Menu/>
    <div>
      <Chart/>
      <ul v-for="(answer, index) in this.$store.getters.getAnswers" :key="index">
        <li>No {{ index + 1 }} : {{ answer.content }}</li>
      </ul>
    </div>
  </div>
</template>

<script>
import Chart from './Chart';

export default {
  components: {
    Chart
  }
}
</script>

グラフはこんな感じ。

まとめ

Chart.js(vue-chartjs)を使うと割と簡単にグラフが作成できます。円グラフや棒グラフなどもあるのでいろいろな場面で使えるではないでしょうか。

リアルタイム性が求めれる場面で Firestore のリアルタイムアップデートも有効です。

似たような場面の実装でこの記事の内容がお役に立てば幸いです。