4

I'm trying to create a linechart, using react-chartjs-2, that has a vertical line when hovering over the datapoints in the chart. Like in this picture below:

Chart requirements

I tried using the chartjs-plugin-annotation plugin, but with mixed results. I managed to create a static line, not understanding how or why it works. How should I achieve this? Am I onto something?

const data = {
    labels: [...week(d)],
    datasets: [
        {
            ...
            data: [10000, 9500, 7000, 4500, 2500, 1500, 500, 0],
        }
    ]
};

var line = [{
    type: "line",
    mode: "vertical",

    // ???
    scaleID: "y-axis-0",
    value: -20000,

    borderColor: "#2984c5",
    borderWidth: 1,
}];

const options = {
    tooltips: {
        xPadding: 20,
        yPadding: 10,
        displayColors: false,
        bodyFontSize: 16,
        bodyFontStyle: 'bold',
    },
    annotation: {
        annotations: line,
    },
    scales: {
        yAxes: [{
            gridLines: {
                drawBorder: false,
                tickMarkLength: 0,
            },
            ticks: {
                fontSize: 14,
                padding: 15,
                max: data.maxY,
                min: 0,
                maxTicksLimit: 6,
                fontColor: "#485465"
            }
        }],
        xAxes: [{
            ticks: {
                padding: 5,
                fontSize: 14,
                fontColor: "#485465",
            },
            gridLines: {
                display: false,
            },
        },

        ],
    },
    responsive: false,
}

I have my full code available here: https://codesandbox.io/s/y28mk3rn4z

Grotle
  • 53
  • 1
  • 6

3 Answers3

3

In case someone needs it for "react-chartjs-2": "^4.0.1".
This one worked for me based on previous answers:

import { Chart } from 'chart.js';
import { Line } from 'react-chartjs-2';

Chart.register(
  {
    id: 'uniqueid5', //typescript crashes without id
    afterDraw: function (chart: any, easing: any) {
      if (chart.tooltip._active && chart.tooltip._active.length) {
        const activePoint = chart.tooltip._active[0];
        const ctx = chart.ctx;
        const x = activePoint.element.x;
        const topY = chart.scales.y.top;
        const bottomY = chart.scales.y.bottom;
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(x, topY);
        ctx.lineTo(x, bottomY);
        ctx.lineWidth = 2;
        ctx.strokeStyle = '#e23fa9';
        ctx.stroke();
        ctx.restore();
      }
    }
  }
);
.
.
.
<Line 
    options={{
      ...options,
      interaction: {
        mode: 'index',
        intersect: false,
      }}} 
    data={data}
  />
David Rios
  • 377
  • 4
  • 9
2

The below answer is correct it only needs some tweaks, Thanks Jordan.

Chart.pluginService.register({
    afterDraw: function(chart, easing) {
        if (chart.tooltip._active && chart.tooltip._active.length) {
            const activePoint = chart.controller.tooltip._active[0];
            const ctx = chart.ctx;
            const x = activePoint.tooltipPosition().x;
            const topY = chart.scales['y-axis-0'].top;
            const bottomY = chart.scales['y-axis-0'].bottom;
            ctx.save();
            ctx.beginPath();
            ctx.moveTo(x, topY);
            ctx.lineTo(x, bottomY);
            ctx.lineWidth = 2;
            ctx.strokeStyle = '#e23fa9';
            ctx.stroke();
            ctx.restore();
        }
    }
});

In the chart options we need to add the below config to display the line on near by hover.

tooltips: {
    mode: 'index',
    intersect: false
},
hover: {
    mode: 'index',
    intersect: false
}

PS: if there are multiple chart plotted together then above piece of code might cause problems. if we want to have this effect on a specific chart(e.g line) then we can add the below condition.

if (
    chart.tooltip._active &&
    chart.tooltip._active.length &&
    chart.config.type === 'line'
)

This worked for me, hope this help.

arfath77
  • 31
  • 3
1

Just looked into this exact thing and this will get you there! It won't do the fills on either side of the line, but it creates the vertical line!

componentWillMount() {
    Chart.pluginService.register({
      afterDraw: function (chart, easing) {
        if (chart.tooltip._active && chart.tooltip._active.length) {
          const activePoint = chart.controller.tooltip._active[0];
          const ctx = chart.ctx;
          const x = activePoint.tooltipPosition().x;
          const topY = chart.scales['y-axis-1'].top;
          const bottomY = chart.scales['y-axis-1'].bottom;
          ctx.save();
          ctx.beginPath();
          ctx.moveTo(x, topY);
          ctx.lineTo(x, bottomY);
          ctx.lineWidth = 2;
          ctx.strokeStyle = '#e23fa9';
          ctx.stroke();
          ctx.restore();
        }
      }
    });
  }

Also for anyone with multiple datasets you can add this into your options for tooltips on all lines at once.

tooltips: {
          mode: 'x'
        },
Jordan Duncan
  • 426
  • 5
  • 14
  • This does not show the vertical line on hover at any point in the chart. The line is only shown when you hover over the exact data point, which is not what the OP wants. – Singh Apr 19 '21 at 13:53