【chart.js】FirebaseAPIで取得したデータを表示しようとするとうまく表示されない


そろそろ娘が起きそうです。ionic2で家計簿アプリ作ってます。
https://qiita.com/irohamaru/items/3df901cd7e12e3c85e9a

家計簿をリスト表示するだけでなく、グラフで収支の推移がわかると便利だなぁと思い、支出・収入グラフの実装をすることにしました。

chart.jsを採用

chart.jsなるものが使えるそうな。
https://liginc.co.jp/web/js/40934

自分のアプリに導入してみたのですが、思ったより簡単にグラフ表示できました。

自分の場合は、Firebaseから取得したデータをグラフ化するのですが、その際に詰まった点が1つありました。

Firebaseからデータを取得するよりも先にグラフが表示されてしまう

どういうことかというと、以下ソースのspendListよりもlineChartが先に描画されてしまい、グラフがうまく表示されない場合があるのです。

sample.html
<!-- canvasタグの部分さえ書いてあれば表示される -->
<ion-card>
  <ion-card-header>
    家計簿ですぞ
  </ion-card-header>
  <ion-card-content>
    <canvas #lineCanvas></canvas>
  </ion-card-content>
</ion-card>
sample.ts
export class HomePage {
  @ViewChild('lineCanvas') lineCanvas;
  lineChart: any;
  public spendList: string[]; // 支出リスト

  ...(省略)...

  constructor(public navCtrl: NavController, public afdb: AngularFireDatabase) {
    ...(省略)...    

    // 支出リスト
    this.spendList = this.getSpendList(...);
  });

  // 支出リストを取得
  // Firebase APIを使ってFirebaseのDBからデータを取得するメソッド
  getSpendList(...) {
    ...(省略)...
    this.afdb.list('kakeibo', {
      ...(省略)...
    }).subscribe(list => {
      ...(省略)...
    });
    return resultList;
  }

 ionViewDidLoad() {
   this.lineChart = new Chart(this.lineCanvas.nativeElement, {
     type: 'line',
     data: {
       labels: this.thisMonthDayList, //今月の日付リスト(1,2,...31)
       datasets: [
         {
           label: '支出',
           fill: false,
           lineTension: 0.1,
           backgroundColor: "rgba(75,192,192,0.4)",
           borderColor: "rgba(75,192,192,1)",
           borderCapStyle: 'butt',
           borderDash: [],
           borderDashOffset: 0.0,
           borderJoinStyle: 'miter',
           pointBorderColor: "rgba(75,192,192,1)",
           pointBackgroundColor: "#fff",
           pointBorderWidth: 1,
           pointHoverRadius: 5,
           pointHoverBackgroundColor: "rgba(75,192,192,1)",
           pointHoverBorderColor: "rgba(220,220,220,1)",
           pointHoverBorderWidth: 2,
           pointRadius: 1,
           pointHitRadius: 10,
           data: this.spendList, // Firebaseから取得する支出データ
           spanGaps: false,
         }
       ]
     });
   }

本当はデータはあるのに、横一列の点の集まりになってしまう。

もしくは、グラフの描画部分にカーソルが触れるとエラー画面が表示されることも。

解決策

支出リストのデータ取得後、意図的にグラフを遅延表示する。
(グラフ表示をsetTimeoutで1000msだけ遅延させる)

sample.ts
export class HomePage {
  @ViewChild('lineCanvas') lineCanvas;
  lineChart: any;
  public spendList: string[]; // 支出リスト

  ...(省略)...

  constructor(public navCtrl: NavController, public afdb: AngularFireDatabase) {
    ...(省略)...    

    // 支出リスト
    this.spendList = this.getSpendList(...);
  }

  ionViewDidLoad() {
    // 支出リストの取得よりグラフが先に表示されないように遅延させる
    setTimeout(() => {
      this.showChart();
    }, 1000);
  }

  showChart() {
    this.lineChart = new Chart(this.lineCanvas.nativeElement, {
      ...(省略)...  
    });
  }

※ionicサンプルプロジェクトのソースを眺めてたら、jsonファイルからデータを引き出すのに時間がかかるため、意図的に処理を遅延させてる箇所があったので参考にしました。

schedule.ts
// simulate a network request that would take longer
// than just pulling from out local json file
setTimeout(() => {
  refresher.complete();

  const toast = this.toastCtrl.create({
    message: 'Sessions have been updated.',
    duration: 3000
  });
  toast.present();
}, 1000);