chartjs / chartjs-plugin-datalabels

Chart.js plugin to display labels on data elements
https://chartjs-plugin-datalabels.netlify.app
MIT License
863 stars 460 forks source link

Add support for change cursor on hover of data labels with chart.js version 3 #295

Closed Tapudp closed 1 year ago

Tapudp commented 2 years ago

I've been trying to change the mouse cursor to 'pointer' as soon as it is hovered on the data label.

I'm effectively able to achive this effect while hovering over data-points, so that is fine.

options: {
onHover: (eve, legendItems, chartElement) => {
      if (_.get(eve, 'native.target.style')) {
        eve.native.target.style.cursor = legendItems[0] ? 'pointer' : 'default';
      }
    }
}

I'm trying to follow this current documentation for the ChartDataLabels Plugin : https://chartjs-plugin-datalabels.netlify.app/guide/events.html#example

listeners: {
          click: ({ datasetIndex, dataIndex }) => {
            setTileActive(report.id);
            populateDrills(report.id, reportGroup, report.data.dataset[datasetIndex].values[dataIndex]);
            executeScroll();
            return;
          },
          enter: async (context) => {
            context.hovered = true;
            const chartTileElem = document.getElementById(`${report.id}-chart`);
            console.log('<><><><', chartTileElem.style.cursor, context);

            // _.set(context, 'chart.canvas.style.cursor', 'pointer');

            _.set(chartTileElem, 'style.cursor', 'pointer');

            // context.chart.canvas.style.cursor = 'pointer';
            return;
          },
          leave: (context) => {
            context.hovered = false;

            // const chartTileElem = document.getElementById(`${report.id}-chart`);
            // chartTileElem.style.cursor = 'default';

            // context.chart.canvas.style.cursor = 'default';
            return;
          },
          color: (context) => {
            return context.hovered ? 'green' : null;
          }
        }

This does re-render the chart but doesn't change the cursor to pointer when needed. One weird behaviour I've found out is that it does change cursor to pointer in some of the bar-charts when the hovered item is of the highest value in that chart. Again, that happens rarely.

So please do suggest any solid solution that would change the cursor on hover of the data label.

The only similar question on Stackoverflow: https://stackoverflow.com/questions/45149062/chart-js-how-to-show-cursor-pointer-for-labels-legends-in-line-chart

differs a lot from this one. As it talks about the onHover behaviour on labels and legends, where as, in this thread I'm trying to find a solution for the data labels that gets rendered on top of the chart's data points.

PS.: I've asked the same question here on stackoverflow : https://stackoverflow.com/questions/70056094/how-to-change-cursor-on-hover-of-data-labels-in-chart-js-version-3

stockiNail commented 2 years ago

@Tapudp Here is the codepen: https://codepen.io/stockinail/pen/RwoxzNZ

I think the usage of aysnc is not correct. The callback are sync and you should return also true to change rendering. See example documentation: https://chartjs-plugin-datalabels.netlify.app/guide/events.html#example

Tapudp commented 2 years ago

@stockiNail For onHovering it doesn't change the cursor for me, for multiple reasons probably. I'm attaching the screenshot.

image

The logs at the time of entering and closing shows the active property to be always null. image

So how do I achieve the required behaviour? I'm not using async that was a mistake in my previous comment. This is my listener code-block:

listeners: {
          click: ({ datasetIndex, dataIndex }) => {
            setTileActive(report.id);
            populateDrills(report.id, reportGroup, report.data.dataset[datasetIndex].values[dataIndex]);
            executeScroll();
            return;
          },
          enter: (context) => {
            context.hovered = true;
            context.chart.canvas.style.cursor = 'pointer';
            console.log('on enter the data labels', context);
            return true;
          },
          leave: (context) => {
            context.hovered = false;
            context.chart.canvas.style.cursor = 'false';
            console.log('on leave of data label', context);
            return true;
          },
          color: (context) => {
            return context.hovered ? 'green' : null;
          }
        }
stockiNail commented 2 years ago

@Tapudp I have changed a little the codepen, to be more close to your use case: https://codepen.io/stockinail/pen/RwoxzNZ

I used your listener configuration but:

  1. I logged only context.hovered and as you can see from log, it is changed every time you enter or leave the label
  2. the color options is not an options of listener but it's an option of label definition. Having color in the listeners node, nothing change form color perspective.

Be also aware, codepen is using ChartJs version 3.6.2 and DataLabels plugin version 2.0.0

stockiNail commented 2 years ago

@Tapudp I see that your are setting the cursor to false but it doesn't seem an acceptable value for cursor: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor In codepen I use default.

Tapudp commented 2 years ago

@stockiNail Yeah that was again something that I was trying with cursor to false, just to see if it changes in consoles. I am aware of using default, thank you for mentioning that.

I've updated the library to "chartjs-plugin-datalabels": "^2.0.0", it was at 2.0.0-rc.2 for some reason. I'm attaching the video portion as it updates the hovered property and also changes the font-size based on it. For some reason, maybe chart is re-rendering or something it doesn't change the cursor pointer, which is the expected behaviour.

I've even tried using the lodash to set this particular nested obejct property, but it doesn't work. 🤒

enter: (context) => {
            _.update(context, 'chart.canvas.style.cursor', 'pointer');

            // context.chart.canvas.style.cursor = 'pointer';
            context.hovered = true;
            console.log('on enter the data labels', context.hovered);
            return true;
          },
          leave: (context) => {
            // context.chart.canvas.style.cursor = 'default';
            _.update(context, 'chart.canvas.style.cursor', 'default');
            context.hovered = false;
            console.log('on leave of data label', context.hovered);
            return true;
          }

https://user-images.githubusercontent.com/8810813/146055878-09dc5ed4-5824-4ac9-876d-6002e2b69118.mov

Tapudp commented 2 years ago

I'm on chartjs version 3.3.3, "chart.js": "3.3.0",

LeeLenaleee commented 2 years ago

As @stockiNail pointed out in his example in this thread and I pointed out in my example in your stack question it is working fine. So please share a reproducable sample with codepen, jsfiddle or codesandbox (if using a framework) so we can better help you since this wont work.

simonbrunel commented 1 year ago

@Tapudp I'm closing this issue since both @stockiNail and @LeeLenaleee examples work as expected and you haven't been able to provide us a way to reproduce your problem.