📈

ChartJSでオリジナルチャート、作れるって知ってました?

2023/12/09に公開

Voicy Advent Calendar 9日目の投稿です。VoicyではAndroidエンジニアをしています。ぬまです。
最近はフロントエンド開発にて、チャート表示機能の開発を携わらせていただきました。
採用したChart.jsについてご紹介したいと思います。

https://qiita.com/advent-calendar/2023/voicy

ChartJSって何?

美しく洗練されたデザインのグラフをあっという間に作れちゃう無料のツールです。
さらに、自分だけのオリジナルチャートを作り上げることも可能です。
採用事例が多いことから信頼性も高いです。
新型コロナウイルスが世界中で猛威を振るっていた過去が久しいですが、その対策サイトを公開している東京都でも、ChartJSが使われています。

はじめに

ChartJSには様々なタイプのチャートがありますが、ここでは以下のグラフを元にカスタマイズ例を紹介します。
筆者の開発環境はAngularTypeScriptを使用しています。
Angularラッパーのng2-chartsを使用しています。

  • line
  • bar
  • doughnut

導入

Chart.jsのインストールや初期設定は基本的に公式ドキュメントを参考にしました。
https://www.chartjs.org/docs/latest/getting-started/installation.html

環境

  • typescript 4.8.4
  • angular 15.2.9
  • chart.js 4.4.0

プラグインの作り方

Chart.jsのプラグインはチャートのデフォルトの挙動やレイアウトをカスタマイズまたは変更する方法です。
必要なAPIを実装したオブジェクトを以下のようにchartに渡してやるだけです。
以下は凡例の下の余白を調整しています。

  this.chartConfig = {
      type: 'line',
      plugins: this.legendMargin,
      ...
  };

  private legendMargin = {
    id: 'legendMargin',
    beforeInit(chart) {
      const fitValue = chart.legend.fit;
      chart.legend.fit = function fit() {
        fitValue.bind(chart.legend)();
        return (this.height += 20);
      };
    },
  };

X軸のラベルを時刻として認識させる方法

タイムスケールは、X軸ラベルに時間や日付・年月を表示するために使用されます。
https://www.chartjs.org/docs/latest/samples/scales/time-line.html

xAxesのtypeにtimeを指定します。
こうすることでtimeオプションの指定が可能です。

    const days = ['2023-09-03', '2023-09-04', '2023-09-05', '2023-09-06'];
    const xlabels: Date[] = days.map((value) => moment(value).toDate());
    this.chartConfig = {
      type: 'line',
      data: {
        labels: xlabels,
        datasets: dataset,
      },
    options: {
        scales: {
            xAxes: [{
                type: 'time',
                time: {
		    unit: 'month',
                    displayFormats: format,
		    ...

特定の日時単位でX軸ラベルを表示したい場合time.unit設定オプションに文字列を渡します。
https://www.chartjs.org/docs/latest/axes/cartesian/time.html#time-units

例えば、月別で表示したいとき'month'、複数年のデータ群の時は'year'を渡すとというふうにグラフに表すデータ群によってX軸のラベル単位を切り分けます。

フォーマットはdisplayFormatsで指定します。

    const displayFormats = {
      day: 'yyyy/MM/dd', // 日付のフォーマットを指定
      week: 'yyyy/MM/dd', // 週のフォーマットを指定
      month: 'yyyy/MM/dd', // 月のフォーマットを指定
      quarter: 'yyyy/MM', // 四半期のフォーマットを指定
      year: 'yyyy', // 年のフォーマットを指定
    };

ツールチップのカスタマイズ

スタイル

ツールチップは、マウスポインタをグラフ上にホバーすると情報を表示するようなUIです。
https://www.chartjs.org/docs/latest/samples/tooltip/html.html
ツールチップ内はhtmlをコーディングしてごっそりスタイルをカスタマイズできます。

let chart = new Chart(ctx, {
    type: 'line',
    data: data,
    options: {
        plugins: {
          tooltip: {
            enabled: false,
            position: 'nearest',
            external: this.externalTooltipHandler,
            callbacks: {
              label: function (context) {
                // 表示する情報をここで操作しツールチップに表示する
                let label =
                  context.chart.data.datasets[context.datasetIndex].label +
                  ':' +
                  this.listenerDatas.find(
                    (data) =>
                      data.label === context.chart.data.datasets[context.datasetIndex].label,
                  ).values[context.dataIndex];
                return label;
              }.bind(this), // tsのフィールド変数を使いたい時はthisをバインドする
	      ...
});

ツールチップの配置

ツールチップの表示位置は標準で'nearest', 'average'がありますが、カスタマイズするにはdeclare moduleでモジュールを定義する必要があります。
https://www.chartjs.org/docs/latest/configuration/tooltip.html#custom-position-modes

declare module 'chart.js' {
  interface TooltipPositionerMap {
    myCustomPositioner: TooltipPositionerFunction<ChartType>;
  }
}
...

    Tooltip.positioners.myCustomPositioner = function (
      elements,
      eventPosition,
    ) {
      if (elements.length === 0) {
        return false;
      }
      const element = elements[0];
      const x = eventPosition.x;
      const y = element.element.y;

      return { x, y };
    };

Lineグラフでの間の塗りつぶし

ChartJSのLineチャートではfillオプションを使って線グラフと線グラフの間の領域を塗りつぶすことができます。

this.chartConfig = {
  type: 'line',
  data: {
      datasets: [
    {
      label: 'graph01',
      data: [420, 240, 530, 760, 900, 890, 790],
      fill: '+1', // 下の線グラフまで塗りつぶす
      backgroundColor: '#018DEC1A', // 塗りつぶしの色
      borderColor: '#018DEC',
      borderWidth: 2,
      yAxisID: 'y01',
    },
    {
      label: 'graph02',
      data: [220, 160, 230, 360, 40, 90, 190],
      backgroundColor: '#2CCBA61A',
      fill: 'start',// X軸まで塗りつぶす
      borderColor: '#2CCBA6',
      borderWidth: 2,
      yAxisID: 'y02',
    },
});

Barグラフを横に倒す

Barグラフの初期状態は垂直です。Barグラフを水平に表示したい場合は、indexAxis='y'をオプションに指定すれば可能です。

this.chartConfig = {
      type: 'bar',
      data: {
        labels: ['熱心なファンの割合'],
        datasets: datasets,
      },
      options: {
        layout: {
          padding: {
            left: 30,
            right: 30,
          },
        },
        indexAxis: 'y',
	...
      }
};

Youtubeのチュートリアルチャンネルは見ておきたい

このチャンネルで2007本ものユースケースが紹介されています。
https://www.youtube.com/@ChartJS-tutorials/videos

まとめ

ChartJSは複雑なデータを分かりやすく視覚化する素晴らしいツールです。そのカスタマイズ性により、さまざまな視覚的表現が可能となります。今回紹介したカスタマイズは一例です。ぜひ自分のニーズに合わせて試してみてください。
参考リンク

Voicyテックブログ

Discussion