angularchart.jsbar-chartlinechartcombo-chart

How to have hover effect on the entire line in line chart in chart js


ngOnInit(): void {   
  var myChart = new Chart('myChart', {
  type: 'bar',
  data: {
    labels: ['Modes'],
    datasets: [
      {
        label: 'A',
        data: [this.data.a],
        borderColor: 'rgba(255,105,180,1)',
        backgroundColor: 'rgba(255,105,180,0.2)',
        barPercentage:0.4,
        borderWidth:2,
        order: 1
      },
      {
        label: 'B',
        data: [this.data.b],
        borderColor: 'rgba(75, 192, 192, 1)',
        backgroundColor: 'rgba(75, 192, 192, 0.2)',
        barPercentage:0.4,
        borderWidth:2,
        order: 2
      },
      {
        label: 'Total Recordings',[![image of current scenario][1]][1]
        data:[this.data.totalrecordings,this.data.totalrecordings],
        type:'line',
        borderColor:'rgba(2,117,216,1)',
        backgroundColor:'rgba(2,117,216,0.2)',
        pointRadius:0,//3,
        pointHoverRadius:0,//4,
        xAxisID:'xAxis2',
        order:0
      }
    ]
  },
  options: {
    responsive: true,
    //hover:{
      //mode:'index',
      // intersect:false
    //},
    plugins: {
      legend: {
        position: 'top',
      },
      tooltip:{
        mode:'index',
        callbacks:{
          title:(ttItems)=> (ttItems[0].dataset.type === 'line' ? '' : ttItems[0].label)
        },
      }
    },
    scales:{
      xAxis:{},
      xAxis2:{
        display:false,
        offset:false,
        labels:[' ',' ']
      }
    }
  },
})

}

I want that when I hover anywhere on the line chart it should show the data. Right now only when I hover over the very start or the end of the line then only I can see data. Also at the end of the line when I hover I can just see the total recordings value but in the start when I hover I am able to see value of all the datasets. Any input would be of great help

image of current scenario


Solution

  • Instead of using a line, you could use a dataset with a single floating bar that can be defined as follows:

    {
      label: 'Total Recordings',
      data: [[data.totalrecordings -0.5, data.totalrecordings + 0.5]]
      categoryPercentage: 1,
      barPercentage: 1,
      ...
    }
    

    Together with this, you'll need to define a tooltip.callbacks.label function that correctly reports totalrecordings.

    tooltip: {
      mode: 'index',
      callbacks: {
        label: ctx => ctx.dataset.label + ': ' + (ctx.datasetIndex == 2 ? data.totalrecordings : ctx.parsed.y)
      }
    }
    

    Please take a look at your amended code and see how it works.

    const data = {
      a: 37,
      b: 50,
      totalrecordings: 87
    }
    
    new Chart('myChart', {
      type: 'bar',
      data: {
        labels: ['Modes'],
        datasets: [{
            label: 'A',
            data: [data.a],
            borderColor: 'rgba(255,105,180,1)',
            backgroundColor: 'rgba(255,105,180,0.2)',
            barPercentage: 0.4,
            borderWidth: 2,
            order: 1
          },
          {
            label: 'B',
            data: [data.b],
            borderColor: 'rgba(75, 192, 192, 1)',
            backgroundColor: 'rgba(75, 192, 192, 0.2)',
            barPercentage: 0.4,
            borderWidth: 2,
            order: 2
          },
          {
            label: 'Total Recordings',
            data: [[data.totalrecordings -0.5, data.totalrecordings + 0.5]],
            borderColor: 'rgba(2,117,216,1)',
            borderSkipped: false,
            backgroundColor: 'rgba(2,117,216,0.2)',
            borderWidth: 2,
            categoryPercentage: 1,
            barPercentage: 1,
            xAxisID: 'xAxis2',
            order: 0
          }
        ]
      },
      options: {
        responsive: false,
        plugins: {
          legend: {
            position: 'top',
          },
          tooltip: {
            mode: 'index',
            callbacks: {
              label: ctx => ctx.dataset.label + ': ' + (ctx.datasetIndex == 2 ? data.totalrecordings : ctx.parsed.y)
            }
          }
        },
        onHover: (evt, activeElems, chart) => {
          const datsetIndex = chart.getElementsAtEventForMode(evt, 'y', {})[0]?.datasetIndex;      
          if (datsetIndex == 2) {
            chart.tooltip.setActiveElements([
              {datasetIndex: 2, index: 0 },
              {datasetIndex: 0, index: 0 },
              {datasetIndex: 1, index: 0 }         
            ]);
            chart.update();
          }
        },
        scales: {
          xAxis: {},
          xAxis2: {
            display: false
          }
        }
      },
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js"></script>
    <canvas id="myChart" width="400" height="300"></canvas>