0

I wanna show tooltips over the line not only on data points. I also tried the chartjs-plugin-crosshair but it doesn't work in V3 of chartjs.

  • 1
    I see you are pretty new to the stackoverflow community. Welcome! Please read the following thread on how to best ask a question: https://stackoverflow.com/help/how-to-ask We are here to help you get through what you have already tried. And in your question there are no indication of your previous tries and where you are stuck. "This isn't working" is not a good question. Hope you find your answer in the community here or somewhere else :) – nima Feb 09 '22 at 09:09

3 Answers3

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>
LeeLenalee
  • 27,463
  • 6
  • 45
  • 69
  • Thanks. I saw this script on `StackOverflow` but it has so many problems and it didn't work at all. first of all `Chart.plugins.register({})` instead of `Chart.register({})`, second `getSortedVisibleDatasetMetas()` is not function, third there is no `args.event.type` we should use `args.type` instead. after all again it didn't work :( – Sanaz Mahmoudi Feb 08 '22 at 11:33
  • Well you are not using chart js v3 then, the things you are listing are V2 syntax. Because as you can see in my html block it is using v3 so you either need to update to v3 locally or update your question that you are not using V3 but V2 instead – LeeLenalee Feb 08 '22 at 11:50
  • I just tried exactly your code on `code editor online` and in your script tag you used v3 – Sanaz Mahmoudi Feb 08 '22 at 15:35
  • Yes I know I am using V3, that is what you are using according to your question but not according to your comment – LeeLenalee Feb 08 '22 at 15:42
  • I don't get it, I just used ur script and it get errors as above said. it didn't run at all – Sanaz Mahmoudi Feb 08 '22 at 15:47
  • Yes that is because then you have chart js V2 installed locally – LeeLenalee Feb 08 '22 at 15:52
  • I don't why when I used via `import chart from package.json(v3.7.0)`, it didn't work but from `CDN` it's ok :/ – Sanaz Mahmoudi Feb 08 '22 at 16:08
  • Maby you installed it with npm or something like that, point stays you are using v2 somehow with what you told me in the comment with what was wrong – LeeLenalee Feb 08 '22 at 16:10
  • I don't know I checked again and install v3 but via importing, it didn't work again. thanks anyway. I can test it via `CDN` now, it's ok – Sanaz Mahmoudi Feb 08 '22 at 16:16
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.

nima
  • 1,645
  • 9
  • 18
  • it's only for showing a line over chart, for showing tooltip between data points we should use `interpolate` mode but it doesn't work for me at all – Sanaz Mahmoudi Feb 13 '22 at 15:12
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/