LoginSignup
14
5

More than 3 years have passed since last update.

[Chart.js]グラフのクリックを検知したい

Last updated at Posted at 2020-09-01

やりたいこと

  • 下図のようなグラフでラベル部分(Januaryなど)をクリックすると詳細ページに遷移するといった動きを実現したかった

スクリーンショット 2020-09-01 23.33.06.png

結論

  • きれいに実装するのは無理だった
  • グラフのクリックを検知してクリックしたのがどの項目か取得することはできた

やり方

Chart.jsをそのまま使うパターン

  • こんなグラフがあったとする
<html>
  <head>
    <meta charset="utf-8" />
    <title>chartjs sample</title>
  </head>
  <canvas id="myChart"></canvas>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
  <script>
    const ctx = document.getElementById('myChart').getContext('2d');
    const chart = new Chart(ctx, {
      type: 'horizontalBar',
      data: {
        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
        datasets: [
          {
            label: 'My First dataset',
            data: [3, 10, 5, 2, 20, 30, 45],
          },
        ],
      },
    });
  </script>
</html>
  • 見た目はこんな感じ
    • 棒グラフの部分にホバーするとツールチップが出る

スクリーンショット 2020-09-01 23.58.38.png

  • クリックイベントを検知
<html>
  <head>
    <meta charset="utf-8" />
    <title>chartjs sample</title>
  </head>
  <canvas id="myChart"></canvas>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
  <script>
    const ctx = document.getElementById('myChart').getContext('2d');
    const chart = new Chart(ctx, {
      type: 'horizontalBar',
      data: {
        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
        datasets: [
          {
            label: 'My First dataset',
            data: [3, 10, 5, 2, 20, 30, 45],
          },
        ],
      },
    });
    // ここから追加
    document.getElementById('myChart').addEventListener('click', e => {
      const elements = chart.getElementAtEvent(e);
      if (elements.length) {
        alert(`${elements[0]._index}: ${elements[0]._model.label}`);
      }
    });
  </script>
</html>
  • 最後の方に処理を追加しました
  • chart.jsのcanvas全体に対するクリックを検知してgetElementAtEventを使うことでいろいろ情報がとれます
  • _indexで何番目の項目_model.labelでラベルの値などとることができます
    • このindexなどを使うことで冒頭に書いたやりたいことで言う遷移先などを判別することができます

スクリーンショット 2020-09-01 23.59.02.png

  • これではラベルのクリックは検知できず棒グラフの部分だけ検知できます
  • ただ、軸の最小値を1以上にするとラベルのクリックも反応するようになりました
    • この辺はたまたまこれでいける要件ならって感じですね
<html>
  <head>
    <meta charset="utf-8" />
    <title>chartjs sample</title>
  </head>
  <canvas id="myChart"></canvas>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
  <script>
    const ctx = document.getElementById('myChart').getContext('2d');
    const chart = new Chart(ctx, {
      type: 'horizontalBar',
      data: {
        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
        datasets: [
          {
            label: 'My First dataset',
            data: [3, 10, 5, 2, 20, 30, 45],
          },
        ],
      },
      // 追加した部分
      options: {
        scales: {
          xAxes: [
            {
              ticks: {
                min: 1,
              },
            },
          ],
        },
      },
    });
    document.getElementById('myChart').addEventListener('click', e => {
      const elements = chart.getElementAtEvent(e);
      if (elements.length) {
        alert(`${elements[0]._index}: ${elements[0]._model.label}`);
      }
    });
  </script>
</html>

Reactを使ったパターン

  • react-chartjs-2を使った場合のやり方です
  • 以下のコマンドでライブラリを事前に追加しておく
yarn add chart.js react-chartjs-2
  • まずはグラフを出すだけだとこんな感じ
App.js
import React from 'react';
import { HorizontalBar } from 'react-chartjs-2';

function App() {
  const data = {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
    datasets: [
      {
        label: 'My First dataset',
        data: [3, 10, 5, 2, 20, 30, 45],
      },
    ],
  };

  const onElementsClick = elements => {
    console.log(elements);
    if (elements.length) {
        alert(`${elements[0]._index}: ${elements[0]._model.label}`);
    }
  };

  return (
    <HorizontalBar data={data} onElementsClick={onElementsClick} />
  );
}

export default App;
  • 見た目はReactじゃない時と同じ
  • クリックの検知を入れるとこんな感じ
App.js
import React from 'react';
import { HorizontalBar } from 'react-chartjs-2';

function App() {
  const data = {
    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
    datasets: [
      {
        label: 'My First dataset',
        data: [3, 10, 5, 2, 20, 30, 45],
      },
    ],
  };
  const onElementsClick = elements => {
    console.log('onElementsClick');
    console.log(elements);
    if (elements.length) {
      alert(`${elements[0]._index}: ${elements[0]._model.label}`);
    }
  };
  return <HorizontalBar data={data} onElementsClick={onElementsClick} />
}

export default App;
  • これでどの項目をクリックしたか検知することができる

最後に

  • Chart.jsがcanvasで描画されるのでこまかいことやろうとすると大変ですね
  • 最低限やりたいことはできそう
14
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
5