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

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

我在创建折线图时遇到了图表 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,
    }
});

我的代码输出如下 WAN MoS 分数图 --

所以当我将鼠标悬停在交点(绘制的)点上时,我希望有一条水平线与相同的垂直线在一起..

请帮助我的朋友..提前致谢。

javascript php graph chart.js linechart
3个回答
18
投票

现在是 2022 年,ChartJS 的当前版本是 4.0.1。因此,我建议使用这个新的实现。

首先,我们定义一个

plugin
。 ChartJS 的插件有一个
id
参数,在本例中少说
corsair

然后我们为插件定义

default
变量,例如
width
color
和行
dash
。此外,我们的插件将具有三个参数:
x
y
draw
x
y
mousemove
事件的值,
draw
代表
inChartArea
参数,该参数定义事件是否发生在图表区域内。

最后,ChartJS 有各种钩子来捕获图表渲染周期的不同部分。在这种情况下,如果事件在图表区域内触发,我们将捕获

afterDraw
钩子,根据
x
y
值绘制垂直和水平线。

const plugin = {
    id: 'corsair',
    defaults: {
        width: 1,
        color: '#FF4949',
        dash: [3, 3],
    },
    afterInit: (chart, args, opts) => {
      chart.corsair = {
        x: 0,
        y: 0,
      }
    },
    afterEvent: (chart, args) => {
      const {inChartArea} = args
      const {type,x,y} = args.event

      chart.corsair = {x, y, draw: inChartArea}
      chart.draw()
    },
    beforeDatasetsDraw: (chart, args, opts) => {
      const {ctx} = chart
      const {top, bottom, left, right} = chart.chartArea
      const {x, y, draw} = chart.corsair
      if (!draw) return

      ctx.save()
      
      ctx.beginPath()
      ctx.lineWidth = opts.width
      ctx.strokeStyle = opts.color
      ctx.setLineDash(opts.dash)
      ctx.moveTo(x, bottom)
      ctx.lineTo(x, top)
      ctx.moveTo(left, y)
      ctx.lineTo(right, y)
      ctx.stroke()
      
      ctx.restore()
    }
  }

const 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
    }
  ]
}
const options = {
  maintainAspectRatio: false,
  hover: {
    mode: 'index',
    intersect: false,
  },
  plugins: {
    corsair: {
      color: 'black',
    }
  }
}
  
const config = {
  type: 'line',
  data,
  options,
  plugins: [plugin],
}

const $chart = document.getElementById('chart')
const chart = new Chart($chart, config)
<div class="wrapper" style="width: 98vw; height: 180px">
  <canvas id="chart"></canvas>
</div>

<script src="https://unpkg.com/[email protected]/dist/chart.umd.js"></script>


15
投票

您可以为从工具提示中获得的 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);
<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>

编辑:

您应该为此使用自定义插件,因为您不会每次移动光标时都进行绘制,并且您可以通过使用自定义插件来强制执行此操作:

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);
<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>

编辑:

更新了 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);
<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>


2
投票

我已经在我的一个项目的previous版本中完成了这一点(但仅限垂直线)。不幸的是,此功能已被删除,但仍可以通过我的 github 访问较旧的源代码文件。

关键是这一段代码:

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 = 0.5;
         ctx.strokeStyle = '#A6A6A6';
         ctx.stroke();
         ctx.restore();
      }
   }
});

另一个需要注意的是,上面的代码适用于 Chart.js 2.8,我知道 Chart.js 的当前版本是 3.1。我还没有阅读有关更新的官方手册,但我个人的经验是,此更新不是 100% 向后兼容 - 所以不确定如果您需要 Chart.js 3 它是否仍然有效。(但您可以尝试 2.8)首先,如果它有效,你可以以某种方式调整代码以使其在 3.1 上工作)

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