Advertisement

Draw a horizontal and vertical line on mouse hover in chart js

阅读量:

题意

在 Chart.js 中在鼠标悬停时绘制水平线和垂直线

问题背景:

I'm encountering challenges in troubleshooting an issue related to creating a line chart using Chart.js. My goal is to produce a chart that accurately represents specified data, along with the requirement of adding both horizontal and vertical lines at intersection points when hovering over them. While successfully implementing a vertical line upon hovering, I haven't yet discovered a reliable method for simultaneously adding both horizontal and vertical lines. Please refer to my code snippets below, which currently demonstrate how to add a vertical line upon hovering.

在使用 Chart.js 制作折线图的过程中遇到了一个问题,在试图根据指定数据制作图表的同时,并且希望在悬停于交点时能够同时显示水平线与垂直线条。然而,在尝试悬停于图表交点时能够绘制出垂直线条的过程中却找不到一种能够同时绘制两条线条的有效方法。以下是我针对悬浮状态中绘制定位竖直线而编写的具体代码片段

复制代码
     window.lineOnHover = function(){  
    
     Chart.defaults.LineWithLine = Chart.defaults.line;
    
     Chart.controllers.LineWithLine = Chart.controllers.line.extend({
    
     draw: function(ease) {
    
       Chart.controllers.line.prototype.draw.call(this, ease);
    
  
    
       if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
    
          var activePoint = this.chart.tooltip._active[0],
    
              ctx = this.chart.ctx,
    
              x = activePoint.tooltipPosition().x,
    
              topY = this.chart.legend.bottom,
    
              bottomY = this.chart.chartArea.bottom;
    
  
    
          // draw line
    
          ctx.save();
    
          ctx.beginPath();
    
          ctx.moveTo(x, topY);
    
          ctx.lineTo(x, bottomY);
    
          ctx.lineWidth = 1;
    
          ctx.setLineDash([3,3]);
    
          ctx.strokeStyle = '#FF4949';
    
          ctx.stroke();
    
          ctx.restore();
    
       }
    
     }
    
     });
    
     }
    
  
    
  
    
 //create chart
    
 var backhaul_wan_mos_chart = new Chart(backhaul_wan_mos_chart, {
    
     type: 'LineWithLine',
    
     data: {
    
     labels: ['Aug 1', 'Aug 2', 'Aug 3', 'Aug 4', 'Aug 5', 'Aug 6', 'Aug 7', 'Aug 8'],
    
     datasets: [{
    
             label: 'Series 1',
    
             data: [15, 16, 17, 18, 16, 18, 17, 14, 19, 16, 15, 15, 17],
    
             pointRadius: 0,
    
             fill: false,
    
             borderDash: [3, 3],
    
             borderColor: '#0F1731',
    
 //                    backgroundColor: '#FF9CE9',
    
 //                    pointBackgroundColor: ['#FB7BDF'],
    
             borderWidth: 1
    
         }],
    
 //                lineAtIndex: 2,
    
     },
    
     options: {
    
     tooltips: {
    
         intersect: false
    
     },
    
     legend: {
    
         display: false
    
     },
    
     scales: {
    
         xAxes: [{
    
                 gridLines: {
    
                     offsetGridLines: true
    
                 },
    
                 ticks: {
    
                     fontColor: '#878B98',
    
                     fontStyle: "600",
    
                     fontSize: 10,
    
                     fontFamily: "Poppins"
    
                 }
    
             }],
    
         yAxes: [{
    
                 display: true,
    
                 stacked: true,
    
                 ticks: {
    
                     min: 0,
    
                     max: 50,
    
                     stepSize: 10,
    
                     fontColor: '#878B98',
    
                     fontStyle: "500",
    
                     fontSize: 10,
    
                     fontFamily: "Poppins"
    
                 }
    
             }]
    
     },
    
     responsive: true,
    
     }
    
 });
    
    
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/Osi1ZT8qbpuHeVgy7w5QtLX2WfoN.png)

my output of the code is as follow in WAN MoS Score graph --

我的代码输出如下,在 WAN MoS 分数图表中 --

Thus, my intention is to establish a horizontal line that also shares a common vertical line upon hovering over its plotted intersection point.

因此,我希望当我悬停在交点(绘制的)上时,在显示区域中能够同时呈现水平线与垂直线。

Please help my guys..Thanks in advance.

请帮助我的团队..提前感谢。

问题解决:

It's possible to add a second draw section for accessing the y value from a tooltip. First, in order to achieve this, one should access the chart area, which is similar to how positions for bottom and top are determined. Subsequently, moving in a straight line towards increasing x values will allow access along this Y axis.

仅需为从提示框中捕获的y坐标增加一个绘图块即可。操作步骤如下:首先将光标移至图表区域左侧位置(可参考捕获底部和顶部位置信息后),接着在该y坐标位置向右拖动光标完成绘图块的添加

复制代码
 Chart.defaults.LineWithLine = Chart.defaults.line;

    
 Chart.controllers.LineWithLine = Chart.controllers.line.extend({
    
   draw: function(ease) {
    
     Chart.controllers.line.prototype.draw.call(this, ease);
    
  
    
     if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
    
       var activePoint = this.chart.tooltip._active[0],
    
     ctx = this.chart.ctx,
    
     x = activePoint.tooltipPosition().x,
    
     y = activePoint.tooltipPosition().y,
    
     topY = this.chart.legend.bottom,
    
     bottomY = this.chart.chartArea.bottom,
    
     left = this.chart.chartArea.left,
    
     right = this.chart.chartArea.right;
    
  
    
  
    
       // Set line opts
    
       ctx.save();
    
       ctx.lineWidth = 1;
    
       ctx.setLineDash([3, 3]);
    
       ctx.strokeStyle = '#FF4949';
    
  
    
       // draw vertical line      
    
       ctx.beginPath();
    
       ctx.moveTo(x, topY);
    
       ctx.lineTo(x, bottomY);
    
       ctx.stroke();
    
  
    
       // Draw horizontal line
    
       ctx.beginPath();
    
       ctx.moveTo(left, y);
    
       ctx.lineTo(right, y);
    
       ctx.stroke();
    
  
    
       ctx.restore();
    
     }
    
   }
    
 });
    
  
    
 var options = {
    
   type: 'LineWithLine',
    
   data: {
    
     labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    
     datasets: [{
    
     label: '# of Votes',
    
     data: [12, 19, 3, 5, 2, 3],
    
     borderWidth: 1
    
       },
    
       {
    
     label: '# of Points',
    
     data: [7, 11, 5, 8, 3, 7],
    
     borderWidth: 1
    
       }
    
     ]
    
   },
    
   options: {
    
   }
    
 }
    
  
    
 var ctx = document.getElementById('chartJSContainer').getContext('2d');
    
 new Chart(ctx, options);
    
    
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/DlXxGt2odWpRZcMJV3PHm6Eezbr5.png)
复制代码
 <body>

    
   <canvas id="chartJSContainer" width="600" height="400"></canvas>
    
   <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
    
 </body>
    
    
    
    
    html

Edit:

You should opt for a third-party library for this purpose since you don’t draw every time you move the cursor. Additionally, you can ensure that your cursor movements are accurately tracked and recorded by using a third-party library:

建议在编辑过程中采用自定义插件以完成此功能。因为每次移动光标并不自动触发绘图操作,请确保配置特定的自定义插件以强制执行此功能:

复制代码
 const options = {

    
   type: 'line',
    
   data: {
    
     labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    
     datasets: [{
    
     label: '# of Votes',
    
     data: [12, 19, 3, 5, 2, 3],
    
     borderWidth: 1
    
       },
    
       {
    
     label: '# of Points',
    
     data: [7, 11, 5, 8, 3, 7],
    
     borderWidth: 1
    
       }
    
     ]
    
   },
    
   options: {
    
     plugins: {
    
       corsair: {
    
     dash: [2, 2],
    
     color: 'red',
    
     width: 3
    
       }
    
     }
    
   },
    
   plugins: [{
    
     id: 'corsair',
    
     afterInit: (chart) => {
    
       chart.corsair = {
    
     x: 0,
    
     y: 0
    
       }
    
     },
    
     afterEvent: (chart, evt) => {
    
       const {
    
     chartArea: {
    
       top,
    
       bottom,
    
       left,
    
       right
    
     }
    
       } = chart;
    
       const {
    
     x,
    
     y
    
       } = evt;
    
       if (x < left || x > right || y < top || y > bottom) {
    
     chart.corsair = {
    
       x,
    
       y,
    
       draw: false
    
     }
    
     chart.draw();
    
     return;
    
       }
    
  
    
       chart.corsair = {
    
     x,
    
     y,
    
     draw: true
    
       }
    
  
    
       chart.draw();
    
     },
    
     afterDatasetsDraw: (chart, _, opts) => {
    
       const {
    
     ctx,
    
     chartArea: {
    
       top,
    
       bottom,
    
       left,
    
       right
    
     }
    
       } = chart;
    
       const {
    
     x,
    
     y,
    
     draw
    
       } = chart.corsair;
    
  
    
       if (!draw) {
    
     return;
    
       }
    
  
    
       ctx.lineWidth = opts.width || 0;
    
       ctx.setLineDash(opts.dash || []);
    
       ctx.strokeStyle = opts.color || 'black'
    
  
    
       ctx.save();
    
       ctx.beginPath();
    
       ctx.moveTo(x, bottom);
    
       ctx.lineTo(x, top);
    
       ctx.moveTo(left, y);
    
       ctx.lineTo(right, y);
    
       ctx.stroke();
    
       ctx.restore();
    
     }
    
   }]
    
 }
    
  
    
 const ctx = document.getElementById('chartJSContainer').getContext('2d');
    
 new Chart(ctx, options);
    
    
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/zVpPam2WHsM546GonQkLtiRK0N7e.png)
复制代码
 <body>

    
   <canvas id="chartJSContainer" width="600" height="400"></canvas>
    
   <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
    
 </body>
    
    
    
    
    html

Edit:

Updated answer for v3

v3 的更新答案

复制代码
 const options = {

    
   type: 'line',
    
   data: {
    
     labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    
     datasets: [{
    
     label: '# of Votes',
    
     data: [12, 19, 3, 5, 2, 3],
    
     borderWidth: 1
    
       },
    
       {
    
     label: '# of Points',
    
     data: [7, 11, 5, 8, 3, 7],
    
     borderWidth: 1
    
       }
    
     ]
    
   },
    
   options: {
    
     plugins: {
    
       corsair: {
    
     dash: [2, 2],
    
     color: 'red',
    
     width: 3
    
       }
    
     }
    
   },
    
   plugins: [{
    
     id: 'corsair',
    
     afterInit: (chart) => {
    
       chart.corsair = {
    
     x: 0,
    
     y: 0
    
       }
    
     },
    
     afterEvent: (chart, evt) => {
    
       const {
    
     chartArea: {
    
       top,
    
       bottom,
    
       left,
    
       right
    
     }
    
       } = chart;
    
       const {
    
     event: {
    
       x,
    
       y
    
     }
    
       } = evt;
    
       if (x < left || x > right || y < top || y > bottom) {
    
     chart.corsair = {
    
       x,
    
       y,
    
       draw: false
    
     }
    
     chart.draw();
    
     return;
    
       }
    
  
    
       chart.corsair = {
    
     x,
    
     y,
    
     draw: true
    
       }
    
  
    
       chart.draw();
    
     },
    
     afterDatasetsDraw: (chart, _, opts) => {
    
       const {
    
     ctx,
    
     chartArea: {
    
       top,
    
       bottom,
    
       left,
    
       right
    
     }
    
       } = chart;
    
       const {
    
     x,
    
     y,
    
     draw
    
       } = chart.corsair;
    
  
    
       if (!draw) {
    
     return;
    
       }
    
  
    
       ctx.lineWidth = opts.width || 0;
    
       ctx.setLineDash(opts.dash || []);
    
       ctx.strokeStyle = opts.color || 'black'
    
  
    
       ctx.save();
    
       ctx.beginPath();
    
       ctx.moveTo(x, bottom);
    
       ctx.lineTo(x, top);
    
       ctx.moveTo(left, y);
    
       ctx.lineTo(right, y);
    
       ctx.stroke();
    
       ctx.restore();
    
     }
    
   }]
    
 }
    
  
    
 const ctx = document.getElementById('chartJSContainer').getContext('2d');
    
 new Chart(ctx, options);
    
    
    
    
    javascript
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/f7ECVceZ5NWLOjihlBHdgFqzrtsQ.png)
复制代码
 <body>

    
   <canvas id="chartJSContainer" width="600" height="400"></canvas>
    
   <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
    
 </body>
    
    
    
    
    html

全部评论 (0)

还没有任何评论哟~