【Chart.js】グラフの背景色を設定する方法

# はじめに
お仕事でグラフを表示するページを作ることがあったので、まぁSVGとかで頑張って描画してもよかったのですが、いくつか要求仕様があったので、せっかくなら便利でオシャレなグラフツールでもないかな～と思って探したところに出てきたのがChart.js。
これを使ってみたところ、見た目もアニメーションもなんだかかわいくてとてもよい！

ところが、**グラフの背景に色をつけたいな～**と思って背景色設定のプロパティを探したところ、どうやら`background-color: 'white';`みたいに**1行で背景色が設定できる便利機能はない**ことが分かりました。
グラフの領域を目立たせたりデザインをよくしたり、背景色を変えるモチベーションは多いと思ったのでデフォルトで設定機能がないのは意外だったのですが、実装にちょっと苦労したので共有。

# Chart.jsについて
私が使用したChart.jsのバージョンは、**3.7.0** です。
今回はChart.jsの基本的なグラフ作成方法の説明は省略します。
（※ Chart.jsは2系と3系で書き方が異なる部分もありますので、お使いのバージョンにご注意ください！）


Chart.js公式ドキュメントは[こちら（Chart.js 3.7.0）](https://www.chartjs.org/docs/3.7.0/)。

特に、この記事を書いている途中でやっと発見したのですが、[こちら(Canvas background)](https://www.chartjs.org/docs/3.7.0/configuration/canvas-background.html)に背景の描画方法がちゃんと載っていました。
ドキュメント検索能力もまだまだ未熟です笑


# グラフ作成
まずは事前準備として簡単なグラフを作成します。
例として折れ線グラフを作ります。

とりあえずHTMLにはcanvasを用意。
```html:HTML
<canvas id="my_graph" ></canvas>
```

次にjavascriptでチャートを作成していきます。
```javascript:javascript
// ラベルとデータ
let label_list = ['09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00']
let data_list = [100, 120, 130, 100, 98, 124, 80, 85, 113, 97]

// データのプロパティ
let set = [{
    data: data_list,            // プロットするデータ
    lineTension: 0,             // 線のベジェ曲線の張力（直線は0を設定）
    borderWidth: 2,             // 折れ線の太さ
    borderColor: "skyblue",     // 折れ線の色
    backgroundColor: "blue",    // プロットの塗りつぶし色
}];

let ctx = document.getElementById('graph').getContext('2d');
let myChart = new Chart(ctx, {
    plugins: [{
        // のちほどここに背景色を描画するプラグインが入ります。
    }],
    type: 'line',
    data: {
        labels: label_list,
        datasets: set,
    },
    options: {
        scales: {
            y: {
                min: 0,
                max: 200,
            },
        },
        plugins: {
            legend: {
                display: false, // 凡例は非表示
            },
        },
    },
});
```
（※`new Chart()`は変数に格納する必要はないのですが、説明の便宜上変数を用意しています。）

これで以下のような折れ線グラフが描画できました。
かわいい！
<img width="500" alt="graph.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/051aa72c-6d8a-2528-4d57-f233021af234.png">

# 背景色の描画方法
先に結論を書きます。
上で示した`myChart`のpluginsについて、以下のように「beforeDraw」に背景色を描画するための関数（適当に`drawBackground`とする）を設定します。
```javascript:javascript
plugins: [{
    beforeDraw: drawBackground
}],
```
drawBackgroundは以下のように定義します。
```javascript:drawBackground
function drawBackground(target) { // 引数はmyChart自身とされる。

    let x_scale = target.scales.x; // x軸プロパティ取得
    let y_scale = target.scales.y; // y軸プロパティ取得

    let left = x_scale.left;       // x軸の左端座標取得
    let top = y_scale.top;         // y軸の上端座標取得
    let width = x_scale.width;     // x軸の幅取得
    let heigh = y_scale.height;    // y軸の高さ取得

    var cvs = document.getElementById(target.canvas.id); // もちろん'my_graph'で直接指定してもOK
    var ctx = cvs.getContext('2d');

    // プロット領域に重なるように、背景色の四角形を描画
    ctx.fillStyle = "dimgray";              // 背景色（今回は濃いグレー）
    ctx.fillRect(left, top, width, height); // 四角形描画
}
```
これで、以下のようにプロット領域に背景色をつけることができました！
（色合いのセンスが抜群に悪いのは不問としてください）
<img width="500" alt="graph_background.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/4e12dd6a-5545-c407-eded-7b3b123aefeb.png">

# 解説
今回の概要を説明すると、Chart.jsで描画するグラフはデフォルトだと背景透過のため、プラグインで**プロット領域にちょうど重なるように色の付いた四角形を先に描画した**、ということです。

`drawBackground`の定義でいきなり`target`とかいう引数が急に登場しますが（もちろん引数名はtargetでなくても何でもよい）、このようにプラグインのbeforeDrawで引数を設定すると、myChart自身が入る仕様になっています。
実際に`myChart`と`target`をそれぞれコンソールに出力してみると同じものだということが分かります。

その中身をちょいと覗いてみると、
<img width="500" alt="myChart_property.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/c5665380-05e9-cfd4-0b16-8e77cf5a62de.png">
といった感じで自分の作ったチャートのプロパティが入っており、赤枠で囲ったようにx軸・y軸のプロパティも格納されています。
そこで更にこの`myChart.scales.x`を開いてみると、x軸左端の座標`left`、幅`width`が入っています。
同様に`myChart.scales.y`には、y軸上端の座標`top`や高さ`height`が入っています。

これらによって、背景色を塗りたいプロット領域の左上の座標、および幅・高さが以下の図のようなイメージで取得できるので、あとはその通りに四角形を描画してあげれば背景色として見えるわけです。
<img width="550" alt="background_explain.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/a22053f7-6613-f819-e90e-35271659d7f1.png">

ここまでわかれば、プロット領域に限らず、特定の領域だけ背景色を置いたり、軸上にまで背景色を拡大させることもできるなーとわかります。
適当に`drawBackground`の四角形描画を変更するとこんな感じ。
```javascript:drawBackground 四角形描画をちょいと変更
context.fillRect(left-50, top-10, width+10, height+30);
```
<img width="500" alt="background_explain_extra.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1337870/35367573-cf0f-ac9d-9947-979d26f42aed.png">

これで背景色描画の自由度があがりましたね！

# おまけ
実は[こちら(Canvas background)](https://www.chartjs.org/docs/3.7.0/configuration/canvas-background.html)にも書いてあるように、CSSで背景色を付けるのが最も簡単な方法のようなのですが、どうやら画像保存などをするときにその背景色が反映されない問題があるようです。
今回の方法であればその問題はクリアするため、まぁ程度問題ではありますが今回の内容の方が汎用性のある推奨方法なのだと思います。

# まとめ
今回はタイトルこそChart.jsで「グラフの背景色を設定する方法」でしたが（検索するならこういうキーワードになると思ったため）、実際には「グラフの背景にうまく四角形を書いて背景色っぽく見せる方法」を紹介しました。

そしてこれが現時点で公式の方法のようですが、もしかしたらそのうち１行で簡単に設定できるようになるのかも知れませんね。

Chart.js、かわいいので皆さんもぜひお試しください！