使用 Chart.js 检测图表部分上方的悬停事件

Detecting hover events over parts of a chart using Chart.js

我已经使用 Chart.js 制作了一个饼图,我想检测何时将鼠标悬停在某个段上。我发现了很多关于操作在将鼠标悬停在段上时出现的工具提示的文档,但是没有关于在出现工具提示时做其他事情的文档。这可能吗?

没有...

ChartJS API 中没有任何内容可以覆盖或扩展工具提示,

但是,解决方法...

可以修改Chart.Tooltipclass的draw方法。当工具提示通常由 ChartJS 呈现时,这将允许您 "do something else"。

您要绑定的绘图方法从源代码的第 1351 行开始:

https://github.com/nnnick/Chart.js/blob/master/src/Chart.Core.js

我知道这已经得到了一个可接受的答案,我不确定这是否满足您的用例,但 Chart js 发布了一个允许自定义工具提示的更新(大约一个月前)。这允许在通常绘制工具提示时自定义函数 运行。他们在 git hub

的样本部分有一个例子

总之你定义了一个自定义函数

 Chart.defaults.global.customTooltips = function(tooltip){//do what you want}

这是他们在示例中给出的示例,其中在 html 工具提示中添加了一些额外的文本。我看到的唯一烦人的事情是不提供触发此工具提示的 segment/point/bar 这真的很方便,因为您可以在知道此信息的情况下对图形做一些事情,但您会获得工具提示数据,这意味着您可以用它做点什么。

Chart.defaults.global.customTooltips = function (tooltip) {
      // Tooltip Element
      var tooltipEl = $('#chartjs-tooltip');
      // Hide if no tooltip
      if (!tooltip) {
          tooltipEl.css({
              opacity: 0
          });
          return;
      }
      // Set caret Position
      tooltipEl.removeClass('above below');
      tooltipEl.addClass(tooltip.yAlign);
      // Set Text
      tooltipEl.html(tooltip.text+ " anythign custom you want");
      // Find Y Location on page
      var top;
      if (tooltip.yAlign == 'above') {
          top = tooltip.y - tooltip.caretHeight - tooltip.caretPadding;
      } else {
          top = tooltip.y + tooltip.caretHeight + tooltip.caretPadding;
      }
      // Display, position, and set styles for font
      tooltipEl.css({
          opacity: 1,
          left: tooltip.chart.canvas.offsetLeft + tooltip.x + 'px',
          top: tooltip.chart.canvas.offsetTop + top + 'px',
          fontFamily: tooltip.fontFamily,
          fontSize: tooltip.fontSize,
          fontStyle: tooltip.fontStyle,
      });
  };
  var pieData = [{
      value: 300,
      color: "#F7464A",
      highlight: "#FF5A5E",
      label: "Red"
  }, {
      value: 50,
      color: "#46BFBD",
      highlight: "#5AD3D1",
      label: "Green"
  }, {
      value: 100,
      color: "#FDB45C",
      highlight: "#FFC870",
      label: "Yellow"
  }, {
      value: 40,
      color: "#949FB1",
      highlight: "#A8B3C5",
      label: "Grey"
  }, {
      value: 120,
      color: "#4D5360",
      highlight: "#616774",
      label: "Dark Grey"
  }];

  var ctx1 = document.getElementById("chart-area1").getContext("2d");
  window.myPie = new Chart(ctx1).Pie(pieData);
  var ctx2 = document.getElementById("chart-area2").getContext("2d");
  window.myPie = new Chart(ctx2).Pie(pieData);
#canvas-holder {
       width: 100%;
       margin-top: 50px;
       text-align: center;
   }
   #chartjs-tooltip {
       opacity: 1;
       position: absolute;
       background: rgba(0, 0, 0, .7);
       color: white;
       padding: 3px;
       border-radius: 3px;
       -webkit-transition: all .1s ease;
       transition: all .1s ease;
       pointer-events: none;
       -webkit-transform: translate(-50%, 0);
       transform: translate(-50%, 0);
   }
   #chartjs-tooltip.below {
       -webkit-transform: translate(-50%, 0);
       transform: translate(-50%, 0);
   }
   #chartjs-tooltip.below:before {
       border: solid;
       border-color: #111 transparent;
       border-color: rgba(0, 0, 0, .8) transparent;
       border-width: 0 8px 8px 8px;
       bottom: 1em;
       content:"";
       display: block;
       left: 50%;
       position: absolute;
       z-index: 99;
       -webkit-transform: translate(-50%, -100%);
       transform: translate(-50%, -100%);
   }
   #chartjs-tooltip.above {
       -webkit-transform: translate(-50%, -100%);
       transform: translate(-50%, -100%);
   }
   #chartjs-tooltip.above:before {
       border: solid;
       border-color: #111 transparent;
       border-color: rgba(0, 0, 0, .8) transparent;
       border-width: 8px 8px 0 8px;
       bottom: 1em;
       content:"";
       display: block;
       left: 50%;
       top: 100%;
       position: absolute;
       z-index: 99;
       -webkit-transform: translate(-50%, 0);
       transform: translate(-50%, 0);
   }
<script src="https://raw.githack.com/chartjs/Chart.js/v1.1.1/Chart.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas-holder">
    <canvas id="chart-area1" width="50" height="50" />
</div>
<div id="canvas-holder">
    <canvas id="chart-area2" width="300" height="300" />
</div>
<div id="chartjs-tooltip"></div>

我的做法稍微简单一些: 假设你已经有一些代码定义了 canvas 之类的 canvas = document.getElementById("chart"); 你的饼图是 window.myPie。您可以使用 onmousemove javascript 事件,或 jQuery hover

canvas.onmousemove = function(evt) {
    var el = window.myPie.getElementsAtEvent(evt);
    //do something with the el object to display other information
    //elsewhere on the page
}

在我的例子中,根据 el[0]._index

的值突出显示 table 行

如果也发现了使用 customTooltip 的小技巧。如果用户将鼠标移到值上并显示工具提示,我搜索了一个解决方案来获取事件。除了原始 Plot 值之外,我主要喜欢在不同的框架中呈现一些详细信息。

var options = {            
  customTooltips: function (tooltip)
  {
    if (!tooltip) return;

    tooltip.custom = false;
    tooltip.draw();
    OnEntrySelected(tooltip.title);
    tooltip.custom = this;
  }
}

自定义工具提示是使用 tooltip.draw() 绘制的,但这会调用自定义方法。我将其设置为 false 以避免递归循环,调用默认行为并获取回调 (OnEntrySelected) 所需的数据,在本例中为 x 轴标签的字符串。只要显示工具提示,就会触发此事件。

v2.0版本:

Chart.defaults.global.hover.onHover = function(x) {
  if(x[0]) {
    var index = x[0]._index;
    // Place here your code
  }
};

2020 年更新:对于 Chartjs 3.5

这是我与 Chartjs 3.5 一起使用的快速修复,用于在将鼠标悬停在甜甜圈或饼图部分上时触发事件。它依赖于使用现有的 onHover option :

onHover : (event, activeElements) => {

    if (activeElements.length > 0) {

            // get active chart element
            let elt = activeElements[0];

            // retrieve element label
            let lbl = elt._model.label;

            // Get element value
            let elt_index = elt._chart.tooltip._data.labels.indexOf(lbl);
            let val = elt._chart.tooltip._data.datasets[0].data[elt_index];

           // trigger your event here :
           // ex for vuejs : this.$emit('element-hovered', { label : lbl, value : val });

       }
       else {
           // No active elements
       }

   }

到目前为止工作正常:)