2017.3.28
2017.4.17

ng2-chatsを使って2つのグラフの表示を切り替える

Angular2でグラフを表示したいなぁ、と思って調べたら ng2-chats というのがありました。

内容的には JavaScriptのライブラリである Chart.js をAngular2のディレクティブとして利用できるようにしたものみたいですが、今回、このモジュールを利用して Line Chart を作成してみました。

こういうの。

基本的にサイトに掲載されているものをそのまま利用して、グラフ用のラベルとデータをこちら側でセットすればすぐに利用できます。

また、今回は1つの表示エリアに対して、2つのデータを切り替えて表示するようにしています。

インストールやモジュールの追加は上記のリンク先に掲載されているのでそちらを参照してください。

目次

  • HTML
  • CSS
  • Typescript
  • 参考リンク

HTML


<button (click)="changeTerm('1w')">1週間</button>
<button (click)="changeTerm('6m')">6ヶ月</button>
<div class="graph-area">
  <div style="display: block;" class="graph-content">
    <canvas baseChart width="960" height="400" *ngIf="lineChartData.length > 0"
                [datasets]="lineChartData"
                [labels]="lineChartLabels"
                [options]="lineChartOptions"
                [colors]="lineChartColors"
                [legend]="lineChartLegend"
                [chartType]="lineChartType"></canvas>
  </div>
</div>

canvas要素のwidth、heightを設定すると、設定したサイズでアスペクト比が固定され、自動でcanvas要素が拡大・縮小します(デフォルトの動作)。ちなみにstyleのwidth、height設定ではうまく表示されませんでした。

[datasets]に最初からデータがセットされていればいいですが、そうでない場合、*ngIfを設定しておかないとエラーが出ます。

CSS


.graph-area {
    position: relative;
    width: 100%;
}
.graph-area:before {
    content:"";
    display: block;
    padding-top: 41.67%;
}
.graph-area .graph-content {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

グラフを切り替える瞬間に要素が前詰めされてしまうのを防ぐため、canvas要素と同じようにアスペクト比固定で拡大・縮小するdiv(graph-area)の設定をしています。

詳しくはこちら(iframe要素のアスペクト比を固定した拡大・縮小 - CSS)を参照。

Typescript


import { Component, OnInit } from '@angular/core';
 
@Component({
})
export class LineChartDemoComponent implements OnInit {
  lineChartData:Array<any> = [];
  lineChartLabels:Array<any> = [];
  lineChartOptions: any = { responsive: true };
  lineChartColors: Array<any> = [
    { // grey
      backgroundColor: 'rgba(148,159,177,0.2)',
      borderColor: 'rgba(148,159,177,1)',
      pointBackgroundColor: 'rgba(148,159,177,1)',
      pointBorderColor: '#fff',
      pointHoverBackgroundColor: '#fff',
      pointHoverBorderColor: 'rgba(148,159,177,0.8)'
    }
  ];
  lineChartLegend: boolean = false;
  lineChartType: string = 'line';

  ngOnInit(): void {
    this.changeTerm('1w');
  }

  changeTerm(term: string): void {
    // 初期化
    this.lineChartData = [];
    this.lineChartLabels = [];

    // データ表示
    setTimeout(() => {
      if(term == "1w"){
        this.lineChartLabels = ['3/22', '3/23', '3/24', '3/25', '3/26', '3/27', '3/28'];
        this.lineChartData = [ {data: [11, 12, 13, 14, 15, 16, 17], label: '1週間のアクセス件数'} ];
      }else if(term == "6m"){
        this.lineChartLabels = ['2016/10', '2016/11', '2016/12', '2017/1', '2017/2', '2017/3'];
        this.lineChartData = [ {data: [101, 102, 103, 104, 105, 106], label: '6ヶ月間のアクセス件数'} ];
      }
    });
  }
}

2つのグラフのデータを切り替えて1つのエリアに表示させていますが、lineChartLabelsにセットしたデータが変わる場合、一度データを初期化して*ngIfの判定でcanvas要素を削除してから別のデータをセットし直すというやり方をしないと、lineChartLabelsにセットした文字列が表示に反映されませんでした。

setTimeout()を利用しているのはこのグラフ用のデータを初期化した状態を画面に反映したかったからです。

参考リンク

Angular】関連記事