如何在ChartJS中跟踪折线图上的点击事件?

问题描述 投票:0回答:1

当我点击折线图中的一条线时,我需要获取对应数据集的索引。所有示例都允许您仅跟踪点的单击,但用户也可以单击一条线。如何实现这一目标? 我正在使用 ChartJS 4

我尝试使用this,但此选项仅跟踪点或条上的点击

javascript chart.js
1个回答
0
投票

由于 API 中可能没有这样的东西,我们将自己处理

click
事件。正如您在代码中看到的,ChartJS 提供了获取鼠标点击位置坐标以及所有数据集中所有数据点位置的方法。所有这些都以像素为单位,对吗?

因此配备了所有点(按顺序),我们可以找到最近的系列。这是通过检查每个系列中到每个线段的距离来实现的。点和线之间的距离公式在解析几何中是众所周知的,因此我实现了一个函数的实现

distanceToLine
我在网上找到了。

// this function finds the nearest dataset to the mouse click
function handleClick(ev) {
  const canvasPosition = Chart.helpers.getRelativePosition(ev, myChart);
  const mx = canvasPosition.x
  const my = canvasPosition.y

  var min_distance = Infinity
  var winner = null

  for (j = 0; j < myChart.data.datasets.length; j++) {
  
    var meta = myChart.getDatasetMeta(j);
    
    for (var i = 0; i < meta.data.length - 1; i++) {
      var x1 = meta.data[i].x
      var y1 = meta.data[i].y
      var x2 = meta.data[i + 1].x
      var y2 = meta.data[i + 1].y

      var distance = distanceToLine(x1, y1, x2, y2, mx, my)
      
      if (distance < min_distance) {
        min_distance = distance
        winner = j
      }
    }
    
  }
  
  console.log("closest dataset: " + winner)
  return winner
}

const ctx = document.getElementById('myChart');

const data = {
  labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
  datasets: [{
      label: '# of Votes',
      data: [12, 19, 3, 5, 2, 3],
      borderWidth: 3
    },
    {
      label: '# of Something',
      data: [2, 13, 4, 15, 12, 6],
      borderWidth: 3
    }
  ]
}

const myChart = new Chart(ctx, {
  type: 'line',
  data: data,
  options: {
    scales: {
      y: {
        beginAtZero: true
      }
    },
    onClick: handleClick,
  }
})


//from: claude.ai
function distanceToLine(x1, y1, x2, y2, mx, my) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  const length = Math.sqrt(dx * dx + dy * dy);

  if (length === 0) {
    // The line segment has zero length, so the distance is the distance from (mx, my) to (x1, y1)
    return Math.sqrt((x1 - mx) ** 2 + (y1 - my) ** 2);
  }

  const t = ((mx - x1) * dx + (my - y1) * dy) / (length * length);

  if (t < 0) {
    // The closest point is (x1, y1)
    return Math.sqrt((x1 - mx) ** 2 + (y1 - my) ** 2);
  } else if (t > 1) {
    // The closest point is (x2, y2)
    return Math.sqrt((x2 - mx) ** 2 + (y2 - my) ** 2);
  } else {
    // The closest point is the perpendicular projection of (mx, my) onto the line segment
    const projX = x1 + t * dx;
    const projY = y1 + t * dy;
    return Math.sqrt((projX - mx) ** 2 + (projY - my) ** 2);
  }
}
<div>
  <canvas id="myChart"></canvas>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.