Chart.jsの使い方

# 目次
| 項番 | 見出し |
|:----:|:-------------|
| 1 | [1. はじめに](#1-はじめに) |
| 2 | [2. Chart.jsの基本概要](#2-chartjsの基本概要) |
| 3 | [3. 実装方法](#3-実装方法) |

# 1. はじめに
現場で初めてチャートを表示する機能を開発しました。そこで使用したライブラリが「__Chart.js__」というライブラリだったので使い方についてまとめました。

今回は、ピカチュウのステータスをチャートに表示する機能を作成します。
![IMG-1160.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/8111bc4c-f1f2-9527-42df-79b39d51f368.jpeg)

# 2. Chart.jsの基本概要
- Chart.jsはJavaScriptのライブラリであり、グラフやチャートをウェブページに表示するために使用されます。

- Chart.jsは __MITライセンス__ の下で提供されており、__再配布__ は自由に行うことができます。ただし、 __商標利用__ については、MITライセンスでは明示的に規定されておらず、商標ポリシーに従う必要があります。

- Chart.jsは __「線グラフ」「棒グラフ」「レーダーチャート」「鶏頭図（けいとうず）」「円グラフ」「ドーナツチャート」「バブルチャート」「散布図」__ のグラフを作成するオプションがあります。また、__「線グラフとレーダーチャート」__ の __fillオプション__ を駆使して __「面グラフ」__ を作成することもできます。

- Chart.jsは、チャートをデフォルトの設定で表示する機能を提供しています。しかし、開発者は自身のプロジェクトやデザインのニーズに合わせて、さまざまなプロパティをカスタマイズすることができます。これにより、 __「チャートの表示形式」「軸の設定」「色やスタイル」「アニメーション」__ などを調整することができ、独自のビジュアル表現を作り出すことができます。開発者はChart.jsの柔軟性を活かして、自身の目的や要件に最適なチャートを開発することができます。

- バージョンごとにプロパティの位置やプロパティ名が異なるので注意してください。

# 3. 実装方法
| 項番 | 見出し |
|:----:|:-------------|
| (1) | [まずはグラフを表示する](#まずはグラフを表示する) |
| (2) | [凡例をカスタマイズする](#凡例をカスタマイズする) |
| (3) | [ツールチップをカスタマイズする](#ツールチップをカスタマイズする) |

## まずはグラフを表示する
任意のHTMLとJSファイルを作成し、以下のコードを記載してください。

<details><summary>サンプルコード</summary>

```:simple_chart_display.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>シンプルなチャート表示</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="js/simple_chart_display.js"></script>
  </head>
  <body>
    <!-- チャートの表示エリア -->
    <canvas id="chart"></canvas>

    <!-- チャート表示ボタン -->
    <button id="displayBtn">表示</button>
  </body>
</html>
```
```:simple_chart_display.js
/**
 * コンストラクタ
 */
function SimpleChartDisplay() {
  this.chart = null;
}

/**
 * JSを読み込み時に行う処理
 */
$(document).ready(function () {
  new SimpleChartDisplay().init();
});

/**
 * 最初に行う処理
 */
SimpleChartDisplay.prototype.init = function () {
  const panel = this;
  $("#displayBtn").click(function () {
    panel.chartDisplay();
  });
};

/**
 * チャート表示処理
 */
SimpleChartDisplay.prototype.chartDisplay = function () {
  // 既存のチャートがあれば破棄
  if (this.chart) {
    this.chart.destroy();
  }
  // canvasから2D描画コンテキストを取得
  const ctx = $("#chart")[0].getContext("2d");
  // チャートを描画する。
  this.chart = new Chart(ctx, this.getChartProperty());
};

/**
 * チャートを描画するためのプロパティの取得
 * @returns チャート描画プロパティ
 */
SimpleChartDisplay.prototype.getChartProperty = function () {
  let chartProperty = {
    // グラフの種類(今回は棒グラフ)
    type: "bar",
    // データ
    data: this.getChartData(),
  };
  return chartProperty;
};

/**
 * チャートに表示するデータのプロパティを取得
 * @returns チャートデータ
 */
SimpleChartDisplay.prototype.getChartData = function () {
  let chartData = {
    // x軸のラベル
    labels: ["HP", "こうげき", "ぼうぎょ", "すばやさ", "とくぼう", "とくこう"],
    datasets: [
      {
        label: "ピカチュウ",
        // グラフのデータ
        data: [211, 146, 116, 194, 136, 149],
      },
    ],
  };
  return chartData;
};

```

</details>

### HTMLのコードの説明
下記はJSの読み込みを行っている部分です。
```:scriptの読み込み
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="js/simple_chart_display.js"></script>
```

Chart.jsを使用する方法は色々ありますが、今回はCDNを利用します。他の方法は以下を参考にしてください。

https://misc.0o0o.org/chartjs-doc-ja/getting-started/installation.html

以下のcanvasタグ内にチャートは表示されます。また、JS側でコンテキストを取得するためにidを設定します。
今回は設定しませんが、表示領域の高さや幅はもちろんCSSで設定できます。
```:チャートの表示領域
    <!-- チャートの表示エリア -->
    <canvas id="chart"></canvas>
```

以下はチャートを表示するときのボタンです。
```:チャート表示ボタン
    <!-- チャート表示ボタン -->
    <button id="displayBtn">表示</button>
```

### JavaScriptのコードの説明
以下はチャートに表示するデータの設定です。
```:データの設定
/**
 * チャートに表示するデータのプロパティを取得
 * @returns チャートデータ
 */
SimpleChartDisplay.prototype.getChartData = function () {
  let chartData = {
    // x軸のラベル
    labels: ["HP", "こうげき", "ぼうぎょ", "すばやさ", "とくぼう", "とくこう"],
    datasets: [
      {
        label: "ピカチュウ",
        // グラフのデータ
        data: [211, 146, 116, 194, 136, 149],
      },
    ],
  };
  return chartData;
};
```
- __labels__ はX軸(横軸)に表示されるデータのラベルです。

- __datasets__ は表示したい実際のデータを設定するプロパティです。チャートは複数ある場合もあるので配列です。

- __label__ はそのデータが何のデータなのかを示すためのプロパティです。特定のグラフに対して何らかの操作を行いたいときなどに指定するために使用します。今回の場合はこれが __「ピカチュウ」__ のデータであることを表します。

- __data__ 実際に表示するチャートのデータです。今回の場合は __「ピカチュウのステータス」__ のデータです。 

- __labels__ と __data__ はともに配列で、基本的に長さは一緒になります。

以下は、実際にチャートを描画する際に使用するプロパティの設定です。
```:描画時に使用するプロパティ
/**
 * チャートを描画するためのプロパティの取得
 * @returns チャート描画プロパティ
 */
SimpleChartDisplay.prototype.getChartProperty = function () {
  let chartProperty = {
    // グラフの種類(今回は棒グラフ)
    type: "bar",
    // データ
    data: this.getChartData(),
  };
  return chartProperty;
};
```
- __type__ はグラフの種類を設定します。コードでは棒グラフを設定しています。
 
- __data__ は描画するデータで1つ前に作成したプロパティを設定します。関数化せずに直接設定もできます。

<table>
  <caption>グラフの種類の設定名</caption>
  <thead>
    <tr>
      <th>グラフの種類</th> <th>設定名</th>
    </tr>
  </thead>
  <tr>
    <td>線グラフ</td> <td>line</td>
  </tr>
  <tr>
    <td>棒グラフ</td> <td>bar</td>
  </tr>
  <tr>
    <td>レーダーチャート</td> <td>radar</td>
  </tr>
  <tr>
    <td>鶏頭図</td> <td>polarArea</td>
  </tr>
  <tr>
    <td>ドーナツチャート</td> <td>doughnut</td>
  </tr>
  <tr>
    <td>円グラフ</td> <td>pie</td>
  </tr>
  <tr>
    <td>バブルチャート</td> <td>bubble</td>
  </tr>
  <tr>
    <td>散布図</td> <td>scatter</td>
  </tr>
</table>

https://misc.0o0o.org/chartjs-doc-ja/charts/


以下はチャートを描画する処理です。
canvasタグで設定したidを指定してコンテキストを取得します。そして、そのコンテキストと上記作成したプロパティをインスタンス生成時の引数に指定することでグラフを表示できるようになります。
また、表示ボタンを2回目以降に押下する際は既存のチャートが残った状態だと作成できないのでチャートがある場合は「destroy()」で一度破棄して再度作成します。
```:チャート描画処理
/**
 * チャート表示処理
 */
SimpleChartDisplay.prototype.chartDisplay = function () {
  // 既存のチャートがあれば破棄
  if (this.chart) {
    this.chart.destroy();
  }
  // canvasから2D描画コンテキストを取得
  const ctx = $("#chart")[0].getContext("2d");
  // チャートを描画する。
  this.chart = new Chart(ctx, this.getChartProperty());
};
```

実行すると以下のようなチャートが表示されます。

<details><summary>実行結果</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/d4e38a9c-1269-a852-bbf7-f00f6ed04563.png)

</details>

## 凡例をカスタマイズする。
任意のHTMLとJSファイルを作成し、以下のコードを記載してください。

<details><summary>サンプルコード</summary>

```:custom_legend_chart_display.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>凡例をカスタマイズ</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="js/custom_legend_chart_display.js"></script>
  </head>
  <body>
    <!-- 凡例エリア -->
    <div class="legendArea"></div>

    <!-- チャートの表示エリア -->
    <canvas id="chart"></canvas>

    <!-- チャート表示ボタン -->
    <button id="displayBtn">表示</button>
  </body>
</html>
```
```:custom_legend_chart_display.js
/**
 * コンストラクタ
 */
function CustomLegendChartDisplay() {
  this.chart = null;
}

/**
 * JSを読み込み時に行う処理
 */
$(document).ready(function () {
  new CustomLegendChartDisplay().init();
});

/**
 * 最初に行う処理
 */
CustomLegendChartDisplay.prototype.init = function () {
  const panel = this;
  // 凡例を作成
  panel.createLegend();

  // 表示ボタンがクリックされたときの処理
  $("#displayBtn").click(function () {
    // チャートを表示
    panel.chartDisplay();

    // チェックボックスとチャートの可視性を同期
    $(".chartCheck").each(function () {
      // チェックボックスのvalueを取得
      const datasetId = $(this).val();
      // チェックボックスのチェック状態を取得
      const isChecked = $(this).is(":checked");
      panel.toggleChart(datasetId, isChecked);
    });
  });

  // チェックボックスの変更イベントにリスナーを追加
  $(document).on("change", ".chartCheck", function () {
    // チェックボックスのvalueを取得
    const datasetId = $(this).val();
    // チェックボックスのチェック状態を取得
    const isChecked = $(this).is(":checked");
    panel.toggleChart(datasetId, isChecked);
  });

  // 初回時はチェックボックスにチェックを入れる。
  $(".chartCheck").prop("checked", true);
};

/**
 * 凡例を作成
 */
CustomLegendChartDisplay.prototype.createLegend = function () {
  let legendArea = $(".legendArea ").empty();

  // ピカチュウの図鑑Noをチェックボックスのvalueとして設定する。
  let pokemonDexNumber = "0025";

  let legend = `<label><input type="checkbox" class="chartCheck" value="${pokemonDexNumber}">ピカチュウ</label>`;

  legendArea.append(legend);
};

/**
 * チャート表示処理
 */
CustomLegendChartDisplay.prototype.chartDisplay = function () {
  // 既存のチャートがあれば破棄
  if (this.chart) {
    this.chart.destroy();
  }
  // canvasから2D描画コンテキストを取得
  const ctx = $("#chart")[0].getContext("2d");
  // チャートを描画する。
  this.chart = new Chart(ctx, this.getChartProperty());
};

/**
 * チャートを描画するためのプロパティの取得
 * @returns チャート描画プロパティ
 */
CustomLegendChartDisplay.prototype.getChartProperty = function () {
  let chartProperty = {
    // グラフの種類(今回は棒グラフ)
    type: "bar",
    // データ
    data: this.getChartData(),
    // オプション
    options: this.getChartOptions(),
  };
  return chartProperty;
};

/**
 * チャートに表示するデータのプロパティを取得
 * @returns チャートデータ
 */
CustomLegendChartDisplay.prototype.getChartData = function () {
  let chartData = {
    // x軸のラベル
    labels: ["HP", "こうげき", "ぼうぎょ", "すばやさ", "とくぼう", "とくこう"],
    datasets: [
      {
        id: "0025",
        label: "ピカチュウ",
        // グラフのデータ
        data: [211, 146, 116, 194, 136, 149],
      },
    ],
  };
  return chartData;
};

/**
 * チャートをカスタマイズするプラグインを取得
 * @returns プラグインプロパティ
 */
CustomLegendChartDisplay.prototype.getChartOptions = function () {
  let chartOptions = {
    plugins: {
      legend: {
        // 凡例の非表示
        display: false,
      },
    },
  };
  return chartOptions;
};

/**
 * チャートの表示・非表示を切り替える
 * @param {*} datasetId チェックボックスの値
 * @param {*} isVisible チェックボックスのON・OFF
 * @returns
 */
CustomLegendChartDisplay.prototype.toggleChart = function (
  datasetId,
  isVisible
) {
  if (!this.chart) {
    // 初期化されていないかnullやundefinedの場合
    return;
  }

  // datasetに設定したidとチェックボックスのvalueに一致するものを抜き出す
  const dataset = this.chart.data.datasets.find((ds) => ds.id === datasetId);

  if (dataset) {
    // 表示・非表示を切り替える
    dataset.hidden = !isVisible;
    // チャートを更新
    this.chart.update();
  }
};
```

</details>

### HTMLのコードの説明
以下のdivタグ内に独自で作成する凡例を表示します。
```:凡例表示エリア
    <!-- 凡例エリア -->
    <div class="legendArea"></div>
```

### JavaScriptのコードの説明
以下は凡例を作成するコードです。
```:凡例を作成
/**
 * 凡例を作成
 */
CustomLegendChartDisplay.prototype.createLegend = function () {
  let legendArea = $(".legendArea ").empty();

  // ピカチュウの図鑑Noをチェックボックスのvalueとして設定する。
  let pokemonDexNumber = "0025";

  let legend = `<label><input type="checkbox" class="chartCheck" value="${pokemonDexNumber}">ピカチュウ</label>`;

  legendArea.append(legend);
};
```

新しくidのプロパティを追加します。このidとチェックボックスのvalueを一致させることで、チャートが複数ある場合に指定したチャートの表示・非表示を制御できるようになります。
```:idを追加
/**
 * チャートに表示するデータのプロパティを取得
 * @returns チャートデータ
 */
CustomLegendChartDisplay.prototype.getChartData = function () {
  let chartData = {
    // x軸のラベル
    labels: ["HP", "こうげき", "ぼうぎょ", "すばやさ", "とくぼう", "とくこう"],
    datasets: [
      {
        id: "0025",
        label: "ピカチュウ",
        // グラフのデータ
        data: [211, 146, 116, 194, 136, 149],
      },
    ],
  };
  return chartData;
};
```

凡例を独自カスタマイズするためには __options__ を設定する必要があります。__options__ にある __plguins__ の __legend__ の __display__ を __false__ にすることでデフォルトで設定してある凡例を消すことができます。
```:凡例を制御するためにオプションを作成
/**
 * チャートをカスタマイズするプラグインを取得
 * @returns プラグインプロパティ
 */
CustomLegendChartDisplay.prototype.getChartOptions = function () {
  let chartOptions = {
    plugins: {
      legend: {
        // 凡例の非表示
        display: false,
      },
    },
  };
  return chartOptions;
};
```
:::note warn
Chart.jsバージョンごとにプロパティを設定する場所が異なります。古いバージョンだと __plugins__ の中ではなく __options__ の直下に __legend__ の設定を行います。
```:
options: {
  legend: {
    // 凡例の非表示
    display: false,
  },
  plugins:{},
}
```
:::

新しく __options__ を追加します。
```:optionsを追加
/**
 * チャートを描画するためのプロパティの取得
 * @returns チャート描画プロパティ
 */
CustomLegendChartDisplay.prototype.getChartProperty = function () {
  let chartProperty = {
    // グラフの種類(今回は棒グラフ)
    type: "bar",
    // データ
    data: this.getChartData(),
    // オプション
    options: this.getChartOptions(),
  };
  return chartProperty;
};
```

以下でチェックボックスON・OFFに合わせてグラフの表示・非表示を切り替えるます。
```:
/**
 * チャートの表示・非表示を切り替える
 * @param {*} datasetId チェックボックスの値
 * @param {*} isVisible チェックボックスのON・OFF
 * @returns
 */
CustomLegendChartDisplay.prototype.toggleChart = function (
  datasetId,
  isVisible
) {
  if (!this.chart) {
    // 初期化されていないかnullやundefinedの場合
    return;
  }

  // datasetに設定したidとチェックボックスのvalueに一致するものを抜き出す
  const dataset = this.chart.data.datasets.find((ds) => ds.id === datasetId);

  if (dataset) {
    // 表示・非表示を切り替える
    dataset.hidden = !isVisible;
    // チャートを更新
    this.chart.update();
  }
};
```

__this.chart.data.datasets__ は配列なのでここからチェックボックスのvalueとdatasetsのidが一致するデータを抜き出しています。
```:
// datasetに設定したidとチェックボックスのvalueに一致するもの抜き出す
this.chart.data.datasets.find((ds) => ds.id === datasetId);
```

抜き出したものがある場合は、__hidden__ のフラグを切り替えて、__update()__ でチャートを更新することで表示・非表示が切り替わります。
```:
 if (dataset) {
    // 表示・非表示を切り替える
    dataset.hidden = !isVisible;
    // チャートを更新
    this.chart.update();
 }
```

初期処理にチェックボックスのイベント処理を追加します。
```:チェックボックスのイベント処理を追加
/**
 * 最初に行う処理
 */
CustomLegendChartDisplay.prototype.init = function () {
  const panel = this;
  // 凡例を作成
  panel.createLegend();

  // 表示ボタンがクリックされたときの処理
  $("#displayBtn").click(function () {
    // チャートを表示
    panel.chartDisplay();

    // チェックボックスとチャートの可視性を同期
    $(".chartCheck").each(function () {
      // チェックボックスのvalueを取得
      const datasetId = $(this).val();
      // チェックボックスのチェック状態を取得
      const isChecked = $(this).is(":checked");
      panel.toggleChart(datasetId, isChecked);
    });
  });

  // チェックボックスの変更イベントにリスナーを追加
  $(document).on("change", ".chartCheck", function () {
    // チェックボックスのvalueを取得
    const datasetId = $(this).val();
    // チェックボックスのチェック状態を取得
    const isChecked = $(this).is(":checked");
    panel.toggleChart(datasetId, isChecked);
  });

  // 初回時はチェックボックスにチェックを入れる。
  $(".chartCheck").prop("checked", true);
};
```

<details><summary>実行結果(チェックあり)</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/897de462-e7c3-ac7b-2ea9-bbee129c337e.png)

</details>

<details><summary>実行結果(チェックなし)</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/350fdfa4-2524-9dcc-ab88-9ac3a3b50823.png)

</details>

:::note warn
今回は、凡例を非表示にして、完全に独自の凡例を作成しましたが、__legend__ 自体には __display__ の他にも色々なプロパティがあるので簡単なカスタマイズならこちらの方が簡単です。以下にいくつかプロパティを紹介します。
- __position__：凡例の位置を指定します。利用可能な値は __top, left, bottom, right__ です。
- __align__：凡例の配置を制御します。利用可能な値は __start, center, end__ です。
- __labels__：凡例のラベルに対するオプションを設定します。以下のサブオプションがあります。
    * __color__：ラベルのテキストの色を指定します。
    * __font__：ラベルのフォントに対する設定です。 
     __例: {size: 12, family: 'Helvetica', style: 'normal'}__
    * __padding__：ラベル間のパディング（余白）を設定します。
    * __boxWidth__：凡例のボックスの幅を指定します。
    * __boxHeight__：凡例のボックスの高さを指定します。
- __onClick__：凡例をクリックしたときのイベントハンドラを指定します。
- __onHover__：凡例の上にマウスがホバーしたときのイベントハンドラを指定します。

<details><summary>サンプル</summary>

```:凡例設定
let myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // data...
    },
    options: {
        plugins: {
            legend: {
                display: true,
                position: 'right',
                align: 'center',
                labels: {
                    color: 'rgb(100, 100, 100)',
                    font: {
                        size: 14
                    },
                    padding: 20,
                    boxWidth: 20,
                    boxHeight: 20,
                    usePointStyle: true
                },
                onClick: function(event, legendItem, legend) {
                    // Custom onClick logic
                },
                onHover: function(event, legendItem, legend) {
                    // Custom onHover logic
                }
            }
        }
    }
});
```
</details>
:::

その他は詳しい情報は以下を確認してください。

https://www.chartjs.org/docs/latest/configuration/legend.html

## ツールチップをカスタマイズする

任意のHTMLとJSとCSSファイルを作成し、以下のコードを記載してください。

<details><summary>サンプルコード</summary>

```:custom_tooltip_chart_display.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ツールチップをカスタマイズ</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="js/custom_tooltip_chart_display.js"></script>
    <link rel="stylesheet" href="css/custom_tooltip_chart_display.css" />
  </head>
  <body>
    <!-- チャートの表示エリア -->
    <canvas id="chart"></canvas>

    <!-- ツールチップ表示エリア -->
    <div id="customTooltip"></div>

    <!-- チャート表示ボタン -->
    <button id="displayBtn">表示</button>
  </body>
</html>
```

```:custom_tooltip_chart_display.js
/**
 * コンストラクタ
 */
function CustomTooltipChartDisplay() {
  this.chart = null;
}

/**
 * JSを読み込み時に行う処理
 */
$(document).ready(function () {
  new CustomTooltipChartDisplay().init();
});

/**
 * 最初に行う処理
 */
CustomTooltipChartDisplay.prototype.init = function () {
  const panel = this;
  $("#displayBtn").click(function () {
    panel.chartDisplay();
  });
};

/**
 * チャート表示処理
 */
CustomTooltipChartDisplay.prototype.chartDisplay = function () {
  // 既存のチャートがあれば破棄
  if (this.chart) {
    this.chart.destroy();
  }
  // canvasから2D描画コンテキストを取得
  const ctx = $("#chart")[0].getContext("2d");
  // チャートを描画する。
  this.chart = new Chart(ctx, this.getChartProperty());
};

/**
 * チャートを描画するためのプロパティの取得
 * @returns チャート描画プロパティ
 */
CustomTooltipChartDisplay.prototype.getChartProperty = function () {
  let chartProperty = {
    // グラフの種類(今回は棒グラフ)
    type: "bar",
    // データ
    data: this.getChartData(),
    // オプション
    options: this.getChartOptions(),
  };
  return chartProperty;
};

/**
 * チャートに表示するデータのプロパティを取得
 * @returns チャートデータ
 */
CustomTooltipChartDisplay.prototype.getChartData = function () {
  let chartData = {
    // x軸のラベル
    labels: ["HP", "こうげき", "ぼうぎょ", "すばやさ", "とくぼう", "とくこう"],
    datasets: [
      {
        label: "ピカチュウ",
        // グラフのデータ
        data: [211, 146, 116, 194, 136, 149],
      },
    ],
  };
  return chartData;
};

/**
 * チャートをカスタマイズするプラグインを取得
 * @returns プラグインプロパティ
 */
CustomTooltipChartDisplay.prototype.getChartOptions = function () {
  let chartOptions = {
    plugins: {
      tooltip: {
        // デフォルトのツールチップを無効
        enabled: false,
        external: function (context) {
          // Tooltip Element
          const customTooltip = $("#customTooltip");

          // コンテキストからツールチップを取得
          const tooltip = context.tooltip;

          // ツールチップが表示されていない場合
          if (tooltip.opacity === 0) {
            customTooltip.css("display", "none");
            return;
          }

          // データポイントの情報を取得
          const dataPoints = tooltip.dataPoints;
          // X軸のラベル
          const label = dataPoints[0].label;
          // Y軸の値
          const value = dataPoints[0].formattedValue;

          // カスタムツールチップの内容を設定
          customTooltip.html(`<label>${label}：${value}</label>`);

          // カスタムツールチップの幅と高さを計算
          const tooltipWidth = customTooltip.outerWidth();
          const tooltipHeight = customTooltip.outerHeight();

          // カスタムツールチップの位置を調整して設定
          const left = tooltip.caretX - tooltipWidth / 2;
          const top = tooltip.caretY - tooltipHeight / 2;
          customTooltip.css("left", left + "px");
          customTooltip.css("top", top + "px");

          // カスタムツールチップを表示
          customTooltip.css("display", "block");
        },
      },
    },
  };
  return chartOptions;
};
```
```:custom_tooltip_chart_display.css
#customTooltip {
  /* positionの指定がないとツールチップのCSSの設定が機能しなくなる */
  position: absolute;
  display: none;
}
```

</details>

### HTMLのコードの説明
以下のdivタグはツールチップをHTMLでカスタマイズしたときに指定するのに必要な領域です。
```:ツールチップ表示エリア
    <!-- ツールチップ表示エリア -->
    <div id="customTooltip"></div>
```

### CSSのコードの説明
HTML要素の配置を制御するために、 __position__ を設定します。これがないとツールチップのCSSの設定(leftやとtopなど)が機能しません。また、 __display: none__ を指定することで特定のアクション（ __データポイントにカーソルを合わせる__ ）などをおこなったときのみツールチップを表示するようにします。
```:
#customTooltip {
  /* positionの指定がないとツールチップのCSSの設定が機能しなくなる */
  position: absolute;
  display: none;
}
```

### JavaScriptのコードの説明
凡例と同じよう __plugins__ に __tooltip__ のプロパティを追加します。
__enabled: false__ でデフォルトのツールチップを無効にします。
__external__ 内でツールチップの表示をカスタマイズする処理を記述します。
以下のようなcontextのプロパティを使用して、いろいろなカスタマイズを行えます。
- __context.tooltip.opacity__：カーソルを合わせているデータポイントの透明度
- __context.tooltip.dataPoints[0].label__：カーソルを合わせているデータポイントのX軸のラベル
- __context.tooltip.dataPoints[0].formattedValue__：カーソルを合わせているデータポイントのY軸の値
- __context.tooltip.caretX__：カーソルを合わせているデータポイントのX軸の位置
- __context.tooltip.caretY__：カーソルを合わせているデータポイントのY軸の位置

今回は、ツールチップがカーソルを合わせたデータのチャートの上にくるようにカスタマイズしています。
```:ツールチップのカスタマイズ処理を追加
/**
 * チャートをカスタマイズするプラグインを取得
 * @returns プラグインプロパティ
 */
CustomTooltipChartDisplay.prototype.getChartOptions = function () {
  let chartOptions = {
    plugins: {
      tooltip: {
        // デフォルトのツールチップを無効
        enabled: false,
        external: function (context) {
          // Tooltip Element
          const customTooltip = $("#customTooltip");

          // コンテキストからツールチップを取得
          const tooltip = context.tooltip;

          // ツールチップが表示されていない場合
          if (tooltip.opacity === 0) {
            customTooltip.css("display", "none");
            return;
          }

          // データポイントの情報を取得
          const dataPoints = tooltip.dataPoints;
          // X軸のラベル
          const label = dataPoints[0].label;
          // Y軸の値
          const value = dataPoints[0].formattedValue;

          // カスタムツールチップの内容を設定
          customTooltip.html(`<label>${label}：${value}</label>`);

          // カスタムツールチップの幅と高さを計算
          const tooltipWidth = customTooltip.outerWidth();
          const tooltipHeight = customTooltip.outerHeight();

          // カスタムツールチップの位置を調整して設定
          const left = tooltip.caretX - tooltipWidth / 2;
          const top = tooltip.caretY - tooltipHeight / 2;
          customTooltip.css("left", left + "px");
          customTooltip.css("top", top + "px");

          // カスタムツールチップを表示
          customTooltip.css("display", "block");
        },
      },
    },
  };
  return chartOptions;
};
```
実行すると以下のようなチャートが表示されます。
<details><summary>実行結果(カスタマイズ前)</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/2daa8ff2-ad0b-6e11-1c07-bff02d28d77a.png)

</details>

<details><summary>実行結果(カスタマイズ後)</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2663952/236f1a54-7b98-e83d-872e-a4d69da4085e.png)

</details>

*****
__随時更新予定...__