ChartJSの線グラフで、閾値以上になったら色を変えたい

## やりたいこと
* ChartJSを使って線グラフを書きたい
* ある一定の値を超えていたら線の色を変えたい

こんな要望をちらほら聞き、どうにか実現出来ないかなぁ。
と思ったので、ゴリ押しでやってみました。

データセットを入れるタイミングで、
「閾値未満は青色」「閾値以上は赤」というデータを分ける方法ももちろんあるのですが
「ある値以上の線」だけを変えたい、という細かな部分に対応出来なかったので、試行錯誤してみました。

## 方針
* 描画後のイベントを取得
* 対象グラフのCanvasをピクセル毎に取得
* ピクセルの位置と色を判定して、書き換える


## 中身
Canvasの線グラフ部分を上書きするような関数を用意しておきます。

```JavaScript
const overwriteCanvas = function () {
  console.log("overwriteCanvas");
  const targetCanvas = document.getElementById("targetCanvas");
  const targetCanvasContext = targetCanvas.getContext('2d');
  const {width, height} = targetCanvas;
  const mainImgData = targetCanvasContext.getImageData(0, 0, width, height);
  const mainData = mainImgData.data;
  //Canvasの各ピクセル毎をみて、色を塗り替える。
  for (let i = 0, len = width * height; i < len; i++) {
    // 高さ180pxから305pxまでの範囲で色を変える
    if (width * 180 < i && i < width * 305) {
      const p = i * 4;
      // RGB(54, 162, 235)を RGB(255, 99, 132) (赤) に変える。
      if (mainData[p] === 54 && mainData[p + 1] === 162 && mainData[p + 2] === 235) {
        mainData[p] = 255;
        mainData[p + 1] = 99;
        mainData[p + 2] = 132;
      }
    }
  }
  targetCanvasContext.putImageData(mainImgData, 0, 0);
}
```

さてさて、こんな関数を用意したものの「いつ動かすか」が問題です。。。

```JavaScript
window.addEventListener('load', () => {
  const ctx = document.getElementById('targetCanvas').getContext('2d');
  window.myLine = new Chart(ctx, config);
  overoverwriteCanvas();
});
```

のように動かしても、ChartJS側の描画タイミングが取れず、用意した関数のほうが早く終わってしまいます。

Promiseでやるか → ダメでした。
青から赤に変化させられるが、
ホバーするとグラフが更新され、色が戻ってしまう現象が起きました。

描画後のタイミングが取れない限りダメってことか...。    
  
そんな中、更新らへんの[ソース](https://github.com/chartjs/Chart.js/blob/2.9/src/core/core.controller.js#L472)を読んでると...

`afterUpdate`っていう、怪しいやーつが、ナンカあるぞ。。。！
さらに読んでいくと、`afterRender`というまさにソレなモノまでありますな。。。


確かに、[ドキュメント](https://www.chartjs.org/docs/latest/developers/plugins.html)を読むと...書いてありますね。
でもPluginって、推測出来んすわ。(ポンコツ)

ってことで！

ChartJSのconfigを設定します

```JavaScript
const config = {
  type: 'line',
  data: {}, // 割愛
  options: {
    responsive: false,
    title: {},    // 割愛
    tooltips: {}, // 割愛
    hover: {},    // 割愛
    scales: {}    // 割愛
  },
  plugins: [{
    // 更新後のイベント
    afterUpdate: function () {
      console.log('afterUpdate');
      overwriteCanvas();
    },
    // 描画後のイベント
    afterRender: function() {
      console.log('afterRender');
      overwriteCanvas();
    }
  }]
}
```

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99988/44e6e8b2-1027-968c-630f-e18c7ebe34b0.gif)

若干ラグはあるものの、それっぽく出来ました。
ホバーした際の挙動はこちら。
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99988/e9a0538e-0f6e-a496-d82a-6a9cd154ed46.gif)

ゆ、許してくれますか？


ソースの全体は[ココ](https://gist.github.com/nbtacksaito/fb1fe087e5078ccfc5d3bfd1224815e9)に置いておきます。

## 出来てないこと
完成したかのようで、出来てない部分があります。
実は横幅を固定していたため、レスポンシブな対応は出来ていません。

```JavaScript
  overwriteCanvas = function () {
      // ... 中略
      if (width * 180 < i && i < width * 305) {
```
このif文はCanvasのサイズが固定であることを前提にしていて、
本来は画面resizeイベントに応じて計算しないとイカン部分でした。

計算方法がいまいち分からんので諦めてます。ごめんなさい。


## 参考文献
[[図解] HTML5 Canvasあれこれ - レイヤー, マスク(ImageData), 全画面でのハマりポイント](https://qiita.com/TR246/items/4b84deadb26f1c450722)