kchoi
kchoi

Reputation: 1215

Moving vertical line when hovering over the chart using chart.js

I've been trying to add a vertical line that shows up with a tooltip when hovering over the chart. But I'm using chart.js 2.6 and the syntax from 1.x seems to be outdated.

I've the following code working for 1.x

var data = {
  labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
  datasets: [{
    data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
  }]
};

var ctx = document.getElementById("LineWithLine").getContext("2d");

Chart.types.Line.extend({
  name: "LineWithLine",
  initialize: function() {
    Chart.types.Line.prototype.initialize.apply(this, arguments);

    var originalShowTooltip = this.showTooltip;
    this.showTooltip = function(activePoints) {

      if (activePoints.length) {
        var ctx = this.chart.ctx;
        var scale = this.scale;
        ctx.save();
        ctx.strokeStyle = '#aaa';
        ctx.beginPath();
        ctx.moveTo(activePoints[0].x, scale.startPoint);
        ctx.lineTo(activePoints[0].x, scale.endPoint);
        ctx.stroke();
        ctx.restore();
      }

      return originalShowTooltip.apply(this, arguments);
    }
  }
});

new Chart(ctx).LineWithLine(data, {
  datasetFill: false,
  lineAtIndex: 2
});
<canvas id="LineWithLine"  style="width: 98vw; height:180px"></canvas>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js"></script>

External link

Anyone know how to make it work for 2.6

Upvotes: 30

Views: 29877

Answers (3)

Rahul Manas
Rahul Manas

Reputation: 95

Try this:

var ctx = this.$refs.canvas.getContext("2d");
// new Chart(ctx, config);
var originalLineDraw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function() {
    originalLineDraw.apply(this, arguments);

    var chart = this.chart;
    var ctx = chart.chart.ctx;

if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
    var activePoint = this.chart.tooltip._active[0];
    var ctx = this.chart.ctx;
    var x = activePoint.tooltipPosition().x;
    var topY = this.chart.scales['y-axis-0'].top;
    var bottomY = this.chart.scales['y-axis-0'].bottom;

    // draw line
    ctx.save();
    ctx.beginPath();
    ctx.moveTo(x, topY);
    ctx.lineTo(x, bottomY);
    ctx.lineWidth = 0.5;
    ctx.strokeStyle = '#eeeeee';
    ctx.stroke();
    ctx.restore();
}
}});

This will definitely help you.

Upvotes: 6

ɢʀᴜɴᴛ
ɢʀᴜɴᴛ

Reputation: 32879

Solution for ChartJS 2.6.0

ꜱᴄʀɪᴘᴛ (ᴇxᴛᴇɴᴅɪɴɢ ʟɪɴᴇ ᴄʜᴀʀᴛ)

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

You would also need to set intersect: false for tooltips.

ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩

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

var chart = new Chart(ctx, {
   type: 'LineWithLine',
   data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
      datasets: [{
         label: 'Statistics',
         data: [3, 1, 2, 5, 4, 7, 6],
         backgroundColor: 'rgba(0, 119, 204, 0.8)',
         borderColor: 'rgba(0, 119, 204, 0.3)',
         fill: false
      }]
   },
   options: {
      responsive: false,
      tooltips: {
         intersect: false
      },
      scales: {
         yAxes: [{
            ticks: {
               beginAtZero: true
            }
         }]
      }
   }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx" height="200"></canvas>

Upvotes: 78

Teocci
Teocci

Reputation: 8996

This question is five years old. Nowadays, we can achieve this using plugins and hook calls in this case beforeTooltipDraw to capture the tooltip.caretX. Also we can use the build-in interaction option to achieve this.

This implementacion works with versions 3.x and 4.0.1 of ChartJS

const $chart = document.getElementById('chart')

const plugin = {
    id: 'verticalLiner',
    afterInit: (chart, args, opts) => {
      chart.verticalLiner = {}
    },
    afterEvent: (chart, args, options) => {
        const {inChartArea} = args
        chart.verticalLiner = {draw: inChartArea}
    },
    beforeTooltipDraw: (chart, args, options) => {
        const {draw} = chart.verticalLiner
        if (!draw) return

        const {ctx} = chart
        const {top, bottom} = chart.chartArea
        const {tooltip} = args
        const x = tooltip?.caretX
        if (!x) return

        ctx.save()
        
        ctx.beginPath()
        ctx.moveTo(x, top)
        ctx.lineTo(x, bottom)
        ctx.stroke()
        
        ctx.restore()
    }
}

const data = {
  labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
  datasets: [{
    data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
  }]
}

const options = {
  type: 'line',
  data,
  options: {
    maintainAspectRatio: false,
    interaction: {
      mode: 'index',
      intersect: false,
    },
    plugins: {
      verticalLiner: {}
    }
  },
  plugins: [plugin]
}

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>

Upvotes: 5

Related Questions