Chartjs-Set Tooltip over line Chartjs

0๐Ÿ‘

You can write a custom implementation for V3 for it:

// Options for the indicators
const indicatorOptions = {
  radius: 4,
  borderWidth: 1,
  borderColor: 'red',
  backgroundColor: 'transparent'
};

// Override getLabelAndValue to return the interpolated value
const getLabelAndValue = Chart.controllers.line.prototype.getLabelAndValue;
Chart.controllers.line.prototype.getLabelAndValue = function(index) {
  if (index === -1) {
    const meta = this.getMeta();
    const pt = meta._pt;
    const vScale = meta.vScale;
    return {
      label: 'interpolated',
      value: vScale.getValueForPixel(pt.y)
    };
  }
  return getLabelAndValue.call(this, index);
}

// The interaction mode
Chart.Interaction.modes.interpolate = function(chart, e, option) {
  const x = e.x;
  const items = [];
  const metas = chart.getSortedVisibleDatasetMetas();
  for (let i = 0; i < metas.length; i++) {
    const meta = metas[i];
    const pt = meta.dataset.interpolate({
      x
    }, "x");
    if (pt) {
      const element = new Chart.elements.PointElement({ ...pt,
        options: { ...indicatorOptions
        }
      });
      meta._pt = element;
      items.push({
        element,
        index: -1,
        datasetIndex: meta.index
      });
    } else {
      meta._pt = null;
    }
  }
  return items;
};

// Plugin to draw the indicators
Chart.register({
  id: 'indicators',
  afterDraw(chart) {
    const metas = chart.getSortedVisibleDatasetMetas();
    for (let i = 0; i < metas.length; i++) {
      const meta = metas[i];
      if (meta._pt) {
        meta._pt.draw(chart.ctx);
      }
    }
  },
  afterEvent(chart, args) {
    if (args.event.type === 'mouseout') {
      const metas = chart.getSortedVisibleDatasetMetas();
      for (let i = 0; i < metas.length; i++) {
        metas[i]._pt = null;
      }
      args.changed = true;
    }
  }
})

var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
  type: "line",
  data: {
    labels: ["January", "February", "March", "April", "May", "June", "July"],
    datasets: [{
        fill: true,
        label: "My First dataset",
        backgroundColor: "rgba(132, 0, 0, 1)",
        borderColor: "rgb(255, 99, 132)",
        data: [0, 10, 5, 2, 20, 30, 45]
      },
      {
        data: [30, 40, 50],
        label: 'My Second Dataset',
        fill: true,
        backgroundColor: "lightgreen",
        borderColor: "green"
      }
    ]
  },
  options: {
    interaction: {
      mode: "interpolate",
      intersect: false,
      axis: "x"
    },
    plugins: {
      tooltip: {
        displayColors: false,
      }
    }
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
<h1>Interpolating line values</h1>
<div class="myChartDiv">
  <canvas id="myChart" width="600" height="400"></canvas>
</div>

0๐Ÿ‘

The following combination of chartjs-plugin-crosshair and chart.js seems to be working fine for me.

"chart.js": "^3.4.0",
"chartjs-plugin-crosshair": "^1.2.0"

I am initiating the Chart object like below:

Chart.register(CrosshairPlugin);

Which can be used properly in an useEffect block:

useEffect(() =>
  Chart.register(CrosshairPlugin);
  return () => {
    Chart.unregister(CrosshairPlugin);
  };
}, []);

And then you can pass the options of the chart like below:

{
  ...,
  options: {
    plugins: {
      crosshair: {
        line: {
          color: "#d1d1d1",
          width: 1,
        },
        sync: {
          enabled: true,
          group: 1,
          suppressTooltips: false,
        },
        zoom: {
          enabled: false,
        },
      }
    }
  }
}

Note that the configurations above, will keep the crosshair pointer synced over all your charts rendered on the same component. You may need to change the behavior here.

0๐Ÿ‘

you can use chartjs-plugin-crosshair

function generateDataset(shift, label, color) {
  var data = [];
  var x = 0;

  while (x < 30) {
    data.push({
      x: x,
      y: Math.sin(shift + x / 3)
    });
    x += Math.random();
  }

  var dataset = {
    backgroundColor: color,
    borderColor: color,
    showLine: true,
    fill: false,
    pointRadius: 2,
    label: label,
    data: data,
    lineTension: 0,
    interpolate: true
  };
  return dataset;
}

var chart1 = new Chart(document.getElementById("chart").getContext("2d"), {
  type: "scatter",
  options: {
    plugins: {
      crosshair: {
        sync: {
          enabled: false
        },
      },

      tooltip: {
        animation: false,
        mode: "interpolate",
        intersect: false,
        callbacks: {
          title: function(a, d) {
            return a[0].element.x.toFixed(2);
          },
          label: function(d) {
            return (
              d.chart.data.datasets[d.datasetIndex].label + ": " + d.element.y.toFixed(2)
            );
          }
        }
      }
    },
    scales: {
      x: {
        min: 2,
        max: 28
      }
    }
  },
  data: {
    datasets: [
      generateDataset(0, "A", "red")
    ]
  }
});
<script src="https://cdn.jsdelivr.net/npm/moment@2.27.0/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.4.0/dist/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment@0.1.1"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-crosshair@1.2.0/dist/chartjs-plugin-crosshair.min.js"></script>

<canvas id="chart" height="100"></canvas>

https://jsfiddle.net/Lb0k2sqx/1/

Leave a comment