chartjs / chartjs-plugin-annotation

Annotation plugin for Chart.js
MIT License
603 stars 325 forks source link

Struggling to use annotations in combination with tooltips #871

Closed goenning closed 1 year ago

goenning commented 1 year ago

I basically want the annotation to follow the tooltip so it highlights the current category where the tooltip is shown.

I have something that is partially working, but it's causing hundreds of updates (you can see the bar flashing on this video)

https://user-images.githubusercontent.com/94755/226977358-84b500ec-8078-4a53-98d5-a01e610a3070.mp4

This is what I have:

{
  type: "line",
  xMin: 3,
  xMax: 3,
  borderColor: "rgba(0, 0, 0, 0.05)",
  borderWidth: (ctx) => {
    console.log(ctx);
    const columns = ctx.chart.data.datasets[0].data.length;
    const chartWidth = ctx.chart.width + 100;
    return chartWidth / columns;
  },
},

And then, on the tooltip I use the external option to render a HTML tooltip, as well as do something like this:

const annotations = chartInstance.options.plugins?.annotation?.annotations;
if (annotations && annotations.length > 0) {
  annotations[0].xMin = tooltip.dataPoints[0].dataIndex;
  annotations[0].xMax = tooltip.dataPoints[0].dataIndex;
  clearTimeout(timer);
  timer = window.setTimeout(() => chart.update("none"), 200);
}

Which it kind of works, but it's not optimal. Also open to other ways of doing this if annotation is not the right plugin for this.

goenning commented 1 year ago

I also tried to use a scriptable xMin, but it doesn't seem to called as I move the mouse around the chart

stockiNail commented 1 year ago

@goenning the annotations are not "designed" for this use case. And probably the best solution could be to implement a custom plugin to draw the highlighted box. Nevertheless I have played a bit on your use case. Not perfect (let me take more time in next days) but it's avoiding the update the chart every time. https://codepen.io/stockinail/pen/BaOGjgx

EDIT: I missed "NOT" in the first sentence

stockiNail commented 1 year ago

I also tried to use a scriptable xMin, but it doesn't seem to called as I move the mouse around the chart

@goenning another hint if I may. Myabe it's not solve your issue but I think you could test the value of xMin and xMax with dataIndex before invoking any update. Have a look again to the codepen: https://codepen.io/stockinail/pen/BaOGjgx I used your code (not with external tooltip but using the ootb one), adding a IF statement to avoid to invoke the update if the data index is not changed with annotation setting.

const annotations = chartInstance.options.plugins?.annotation?.annotations;
if (annotations && annotations.length > 0 && annotations[0].xMin !== tooltip.dataPoints[0].dataIndex) {
  annotations[0].xMin = tooltip.dataPoints[0].dataIndex;
  annotations[0].xMax = tooltip.dataPoints[0].dataIndex;
  clearTimeout(timer);
  timer = window.setTimeout(() => chart.update("none"), 200);
}

Seeing my codepen, you can see that the amount of updates on chart are really limited, every time you hover a different dataset item. I have added the title of the chart which is showing how many updates have been performed against the chart. Let me know if this is solving your issue.

goenning commented 1 year ago

I just had to add another instruction to set the annotation.display = false when the tooltip is removed, worked exactly like I wanted.

Thanks @stockiNail 👍