Chart.jsで折れ線グラフを作るときの小ネタ

# はじめに
アドベントカレンダー8日目はJSライブラリのChart.jsの小ネタ紹介です。
2022年前半頃に求人統計データをグラフで表現するためにChart.jsを利用しました。
Chart.jsはかんたんにグラフが導入できるライブラリではありますが、細かいレスポンシブな対応やデザインの調整で苦労したので振り返りも兼ねてTipsを紹介しようと思いました。

## 対象となる読者
- グラフのJSライブラリを選定中の方
- 本記事で紹介するChart.jsの折れ線グラフTipsを求めていた方(コピペ歓迎)

## 実行環境
chart.js v3.7.1
google chrome v107

# ChartJSとは？
棒グラフや円グラフ、レーダーチャートが描画できるOSSのJSライブラリです。

https://www.chartjs.org/docs/latest/

### なぜ選定したか？
Chart.jsの他にも[Highcharts](https://www.highcharts.com/)や[Google Charts](https://developers.google.com/chart)なども選択肢にありました。
それぞれ基本的なデザイン要求は満たせそうではありましたが以下が決め手となりました。

- OSSであること
- 日本語の技術記事が充実している


# Chart.js Tips
やりたいこと、実現方法、サンプルコードをセットでを3つ紹介します。
(すぐに真似できるようにこういった構成にしています。)

- アスペクト比をレスポンシブに変更
- 目盛線やインデックスの表示/非表示
- 余白をいい感じに調整

## アスペクト比をレスポンシブに変更
#### やりたいこと
スマホとPCのレスポンシブ対応のために、それぞれで別のアスペクト比でグラフを表示したい。
cssではなくてJS側で制御したい。

#### 実現方法
描画領域に従ってアスペクト比を固定するため`aspectRatio`を動的に指定します。
contextを引数に取る関数を値として設定することによって画面幅に応じたアスペクト比を指定することができます。
`Scriptable Option`については他のoptionでも利用できるのでライブラリのソースコードを見てみてください。
| スマホ版 | PC版 |
|:-:|:-:|
| <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/7af4af96-9a7f-b10c-08ff-afbfb19dbe5c.png">  | <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/f464592b-a3d4-d4a6-0b4b-b9cb67287f01.png">  |
```javascript
  // グラフの描画領域幅が700を超えたときにアスペクト比変更
  chartOptions: {
    aspectRatio: function(context) {
      return context.chart.width > 700 ? 3.0 : 1.5;
    },
  }
```

ちなみに単純な描画領域によるレスポンシブであれば `maintainAspectRatio: false`とoptionに指定することで実現できます。

## 目盛線やインデックスの表示/非表示
#### やりたいこと
1本１本の間隔が狭いので目盛線を一定間隔で表示するようにしたい。
インデックスもすべて表示すると煩い見た目になるため、表示するものを絞りたい。

#### 実現方法
任意の条件で色などを設定できます。
特定条件で非表示にしたい場合はcolorを背景色と同じにすることで実質的に非表示としました。

| optionなし | optionあり |
|:-:|:-:|
| <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/7af4af96-9a7f-b10c-08ff-afbfb19dbe5c.png">  | <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/96eb8dbb-a0c2-3b4e-f2df-c3af722756dc.png">  |

```javascript
  chartOptions: {
    scales: {
      x: {
        // 奇数のインデックスだけ表示する
        ticks: {
          color: function(context){return context.index%2 === 1 ? "#878787" :"#FFFFFF"},
        },
        // 奇数の目盛線だけ表示する
        grid: {
          color: function(context){return context.index%2 === 1 ? "#F0F0F0" :"#FFFFFF"},
        },
      },
     }
   }
```


## 余白をいい感じに調整
#### やりたいこと
グラフの描画領域のギリギリまで折れ線が到達してしまい見栄えが悪いので、上下の目盛りと接近したときだけ余白を設定したい。
だけど接近していないときは余白は設定したくない。

#### 実現方法
scalesの内の`grace`に値を指定することでデータの最大、最小値に応じて余裕を持って描画することができます。
| grace指定なし | grace指定あり |
|:-:|:-:|
| <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/93ba5af3-ce0a-e1cf-67ac-9f4d6f3c2517.png">  | <img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297148/c0d834ba-21a7-cd50-4459-ff09fd7dd549.png">  |
```javascript
  chartOptions: {
    scales: {
      // 最小値/最大値から少なくとも10%の余白を確保する
      y: {
        grace: "10%",
      },
    },
  }
```


例では`%`で指定していますが数値を指定することにより明示的に余白の拡大ができます。
ただし、データが変動する場合は`%`で設定しておくのが安心だと思います。
https://www.chartjs.org/docs/3.7.1/axes/cartesian/linear.html#grace

# 終わりに
普段はサーバーサイドの開発に携わることが多いので、慣れないフロントエンドの開発に大変苦労しました。
Chart.js導入、活用にあたっては多くのQiitaや技術ブログの記事のおかげで乗り切ることができました。
この記事も誰かの開発の助けになれば幸いです。


## 参考情報
https://www.chartjs.org/docs/3.7.1/
https://github.com/chartjs/Chart.js