Chart.js 2 の散布図で hover イベントを使ってマーカーのスタイルを変える

はじめに

前回の「Chart.js 2 の散布図でツールチップを変更する方法」ではマウスオーバー時に表示されるツールチップのカスタム方法をご紹介しました。

今回は Chart.js 2 の散布図で hover イベントを使って、マーカーのスタイルを変更する方法をご紹介します。サンプルプログラムでは、マーカーの大きさを変更します。

動作確認で使用したのは Chart.js 2.9.3 です。

目次
  1. 下準備
  2. hover 時にマーカーサイズを変更
  3. おわりに

1. 下準備

今回使用した HTML と js です。散布図の実装方法については「Chart.js 2 で散布図(Scatter plot)を実装する方法」で紹介しています。

/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>散布図(Scatter plot)</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
  <script>
    // データ
    var plotData = {
      group1: [
        { x: 1,  y:  81}, { x: 1,  y: 124}, { x: 2,  y: 130},
        { x: 2,  y: 101}, { x: 3,  y: 137}, { x: 3,  y: 132},
        { x: 3,  y: 152}, { x: 4,  y: 137}, { x: 5,  y: 134},
        { x: 5,  y: 142}, { x: 6,  y: 149}, { x: 7,  y: 152},
        { x: 8,  y: 158}, { x: 9,  y: 155}, { x: 10, y: 166},
      ],
      group2: [
        { x: 1,  y:  41}, { x: 1,  y: 121}, { x: 1,  y: 100},
        { x: 2,  y:  96}, { x: 3,  y: 113}, { x: 4,  y:  89},
        { x: 5,  y: 124}, { x: 5,  y: 137}, { x: 5,  y: 151},
        { x: 6,  y: 161}, { x: 6,  y: 130}, { x: 7,  y: 126},
        { x: 7,  y: 122}, { x: 9,  y: 149}, { x: 10, y: 205},
      ]
    }
  </script>
  <script src="js/app.js"></script>
</head>
<body>
  <canvas id="chart-area" width="640" height="320"></canvas>
</body>
</html>
/js/app.js
window.onload = function () {
  var data = {
    datasets: [
      {
        label: 'Group1',
        data: plotData.group1,
        backgroundColor: 'rgba(0, 159, 255, 0.45)',
        borderColor: 'rgba(0, 159, 255, 0.5)',
      },
      {
        label: 'Group2',
        data: plotData.group2,
        backgroundColor: 'rgba(255, 48, 32, 0.45)',
        borderColor: 'rgba(255, 48, 32, 0.5)',
      },
    ],
  };

  var options = {
    responsive: false,
    legend: {
      align: 'start',
      position: 'right',
      labels: { padding: 15 }
    },
    scales: {
      xAxes: [{
        scaleLabel: {
          display: true,
          labelString: 'プレイ回数',
        },
        ticks: { min: 0 },
      }],
      yAxes: [{
        scaleLabel: {
          display: true,
          labelString: 'スコア(点)',
        },
        ticks: { min: 0 }
      }]
    },
  };

  var ctx = document.getElementById('chart-area').getContext('2d');
  var myChart = new Chart(ctx, {
    type: 'scatter',
    data: data,
    options: options,
  });
}

2. hover 時にマーカーサイズを変更

今回のサンプルでは hover イベントを使ってマーカーのサイズを制御します。マウスが乗っているマーカー1つだけのサイズ変更は datasets の pointHoverRadius で設定できるのですが、今回は hover しているデータセットの全マーカーを大きくして、それ以外は小さくします。

app.js に下記のように追記してください。

/js/app.js
window.onload = function () {
  // ▼ これを追加
  var defaultRadius = 4; // 初期表示のマーカーサイズ
  var largeRadius = 5;   // 大マーカー
  var smallRadius = 2;   // 小マーカー

  var data = {
    datasets: [
      {
        ...
        // ▼これを追加
        pointRadius: defaultRadius,
        pointHoverRadius: largeRadius,
      },
      {
        ...
        // ▼これを追加
        pointRadius: defaultRadius,
        pointHoverRadius: largeRadius,
      },
    ],
  };

  var options = {
    ...
  };

  // ▼これを追加
  var prevHoveredIndexes = [];
  options.events = ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove', 'hover'];
  options.onHover = (event, hoveredItems) => {
    // マウスが乗っているマーカーの datasets のインデックス
    var hoveredDatasetIndexes = hoveredItems.map(x => x._datasetIndex);
    // 直前の状態から変更がない場合は処理しない
    if (hoveredDatasetIndexes.toString() === prevHoveredIndexes.toString()) {
      return;
    }
    prevHoveredIndexes = hoveredDatasetIndexes;
    // 各データセットのマーカーサイズを変更
    myChart.data.datasets.forEach((dataset, i) => {
      var radius = defaultRadius;
      // マウスが乗っているマーカーがある場合
      if (hoveredDatasetIndexes.length > 0) {
        // マウスが乗っているマーカーは大きく、それ以外は小さく
        radius = (hoveredDatasetIndexes.includes(i)) ? largeRadius : smallRadius;
      }
      myChart.data.datasets[i].pointRadius = radius;
    });
    // グラフを更新
    myChart.update({ duration: 200 });
  };

  var ctx = ...
}

hover 時の挙動は options.events と options.onHover を使って実装できます。

options.events は、下記公式ドキュメントにある初期値の
['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove']
に hover を追加しています。

今回のサンプルに関しては、['mousemove', 'hover'] でも動くのですが、'click' がないと凡例クリックでの 表示 / 非表示 の切り替えが動かなくなります。

また options.onHover はマウスを動かす度に発火するので、状態変化がない場合は処理をしないようにしています。これをしないと、ツールチップが正常に消えない現象が発生しました。

.update() の引数で指定できるオプションは、下記ページで説明されています。

3. おわりに

イベントに関して、公式ドキュメントにページはあるものの、サンプルコードがほとんどなく、Chart.js のソースコードを見ながら試行錯誤で作りました。

ただ一度分かってしまえば、マーカーの透過度を変えるなど、色々なことができそうですね。今後は他のグラフでも試してみようと思っています。