Help us understand the problem. What is going on with this article?

Chart.js でインタラクティブなチャートを作る方法

More than 1 year has passed since last update.

ウェブの画面にグラフを書きたい時に便利なJSライブラリChart.jsは、とても便利です。
単にチャートを書くだけでなく、チャートをクリックしたりマウスオーバーした際に、そのチャート上のデータを読み取る
ことができます。

マウスのクリックした時に、その時のカーソルの下にあるデータの取り方を紹介します。

サンプルコードはこちら。

マウスオーバーは簡単にできる。けど…

グラフ上の点をマウスオーバーした際の点に対応するデータを取るのは、options.tooltips.callback を使うと簡単にできます。
例えば、マウスオーバーした時に表示されるツールチップのタイトルを現在時刻にするには、
下のように設定する。

new Chart(ctx, 
  type: 'scatter',
  dataset: [{
    data: [
      { x: 1, y: 2},
      { x: 2, y: 2},
      { x: 3, y: 3}
    ]
  }],
  options: {
    tooltips: {
      callbacks: {
        title: function(tooltipItems, data) {
          return new Date().toLocaleTimeString();
        }
      }
    }
  }
);

コールバック関数を設定できる種類やそれに渡される引数については、ドキュメントを参照してください。

しかし、これはあくまでもtooltipを描画するためのものであり、データを取るものではない。また、現在高まっている衝動は、クリックした時に対応したデータを取りたいという欲求である。

getElementAtEvent を使おう

クリック時のイベントを元に、そのイベントが発生した場所にあるデータを返してくれるAPIがgetElementAtEvent だ。
グラフを描画しているCanvas上のクリックイベントを拾うために、イベントハンドラを登録し、その内部で呼び出す。例えば、こんな感じ。

var myCanvas = document.getElementById('myCanvas');
var ctx = myCanvas.getContext('2d');
var myChart = new Chart(ctx, ...);

myCanvas.addEventListener('click', function(event) {
  let item = myChart.getElementAtEvent(event);

  if (item.length == 0) {
    console.log('no element found.')
    return;
  }

  item = item[0];
  let data = item._chart.config.data.datasets[item._datasetIndex].data[item._index];
  alert(`Clicked at (${data.x}, ${data.y})`);   
});

getElementAtEventは、与えたイベントに対応するデータが無ければ空の配列を返します。ですので、データの存在の有無は、その配列の長さで判断できます。

ということで、インタラクティブなチャートを作れそうですね。

同一座標にある複数のデータを取得するには、

複数のデータを取得できるgetElementsAtEventを試してみたのですが、関係ないデータが取れてしまう問題に直面しました1

それとは別に、イベントのハンドリングをhoveronClickまたはonHoverで設定できます。

Chartのコンストラクタに渡すoptionsに、以下のように渡します。

options: {
    hover: {
        mode: 'point'
    },
    onClick: function(event, elements) {
        console.log(`Found ${elements.length} elements`);

        elements.forEach(function(element) {
            let point = myChart.data.datasets[element._datasetIndex].data[element._index];
            console.log(point);
        })
    }

hover は、一見hover時のみの挙動を決めるように見えますが、マウスイベントに対しての挙動を決める設定です。後に設定するcallback関数をどのイベントで呼び出すかは、別途、options.eventsプロパティで設定します。デフォルトは全てのイベントで呼びだされます。
options.hover.modeは、マウスカーソルを基準にどういった点を選択の対象にするかを設定するオプションです。デフォルト値のnearestは最もカーソルに近い一点を選択します。今回は同一の座標点全てを取得したいので、pointを指定しています。他にもオプションがあるので、ドキュメントを参照ください。

今回はクリック時のマウスカーソル下にあるデータ点を取りたいので、onClickを実装します。onClickで指定した関数に渡される引数は、発生したイベントと、そこに関連するデータ点の配列の2つです。データ点の配列は、先のgetElementAtEventの返り値と同じChartElementのオブジェクトの配列です。ChartElementのオブジェクトは、何番目のdatasetのデータなのかを指す_datasetIndex、さらにその中の何番目のデータ点なのかを表す_indexを持っているので、それらを用いて、マウスカーソル下のデータ点を取得できます。

参考


  1. 原因がまだわかっていませんが、とりあえずGitHubのChartjsのリポジトリにレポートしようと思います。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away