Chart.js: How to listen for clicks on labels?

Created on 18 Jun 2016  路  15Comments  路  Source: chartjs/Chart.js

v2.1.6

My use case must be pretty common so I bet it has been solved but I can't find anything in the docs. I have a horizontal bar chart. When the user focuses on a category (clicks the bar), I show detailed info elsewhere in the view.

Often a category has value=0, so there is no bar to click on. Ironically these are the categories most interesting to my user (a low bar means a problem that requires the user's attention) so I still need to give the user a way to show the category details in the view. Any user would expect that he could just click the category name (the yAxis label in my horizontal bar chart) to select that category. So my problem is simple: What's the cleanest way to detect which label was clicked on?

support

Most helpful comment

@etimberg Actually, your fix works! Index 0 was not getting printed because I would only print if value was truthy, and zero failed the if(value) check. Changing the check to if(value!==null) fixes that.

Thanks a bunch.

All 15 comments

There is a method on the scale to go from the pixel to the correct label. I am on mobile so i can't post a fiddle, but the zoom and pan plugin in the chartjs organization uses it

Thanks. I've just gone through the scales docs and I don't see such a function. Could it be undocumented or am I missing it?

I don't think it is currently documented. The bit in the zolm and pan plugin is in panNumericalScale in https://github.com/chartjs/Chart.Zoom.js/blob/master/src/chart.zoom.js

Thanks for putting me on the right track. The panNumericalScale you linked to uses a getValueForPixel() function that looks promising in Chart.js 2.1.6, on line 9058. However I'm not sure how to call it. I define the chart:

var _Chart = new Chart(this.ctx, {
    type: _type,
    data: _data,
    options: _options
});

I then try to access the function of interest by making one of the following calls inside the onClick callback (e is the MouseEvent) generated by the click:

Chart.getValueForPixel(e.ClientX); // error: ...is not a function
this._Chart.getValueForPixel(e.ClientX); // error: ...is not a function
this._Chart.scale.getValueForPixel(e.ClientX); // error _Chart.scale is undefined

The chart renders normally so I know that Chart.js loaded successfully. I just don't know how to refer to that function

Those functions are on a particular scale. Scales can be found in chartInstance.scales which is a map of string scale ID to the scale object. You can find the right scale then call things on it.

@RoxKilly did you get this working? If so, can you please close this issue?

No I haven't gotten it working. Thanks to your help I'm now able to call the function in question with chart.scales[axisName].getValueForPixel(). However I don't get consistent results. To see what I mean, take a look at this plunkr (in file app/app.component.ts).

To see what I'm trying to capture, use the input above the chart to select how many bars you want on the chart, then press the button next to the input. Once the chart is built, click the y-axis labels (not the data bars) and the result of calling getValueForPixel on the y-axis scale will be shown on screen. Notice that:

  • With 2 through 3 bars, clicking the first y-label makes getValueForPixel()==1
  • With 4 through 6 bars, clicking the first y-label makes getValueForPixel()==2
  • With 7 through 9 bars, clicking the first y-label makes getValueForPixel()==3
  • With 10 through 11 bars, clicking the first y-label makes getValueForPixel()==4
  • With 12 through 14 bars, clicking the first y-label makes getValueForPixel()==5

Because I don't have a reliable pattern, I still don't know how to get the text of the yLabel that was clicked.

@RoxKilly I got your plunkr working a bit better here. I used Chart.helpers.getRelativePosition to get the position on the canvas because there are a number of cases that need to be handled (device pixel ratio, margins, padding, etc).

It works a bit better :) For some reason the first label is not shown on the first label (index 0). Not sure why.

Thanks for moving the ball forward on this. I was pretty frustrated before but I'm encouraged now.

@etimberg Actually, your fix works! Index 0 was not getting printed because I would only print if value was truthy, and zero failed the if(value) check. Changing the check to if(value!==null) fixes that.

Thanks a bunch.

@RoxKilly awesome. Glad it works 馃槃

I celebrated too soon it seems. The results of getValueForPixel are thrown off when either a title or legend is displayed above the chart. At this plunk, you'll notice that if you click the top half of the first label's vertical span (The span between the two ticks that segment the label), you get the right result (index 0), but if you click the second half, still within the tick marks that demarcate the first label, you get the wrong result (index 1). This can be repeated with the other labels. Although the plunk I linked to doesn't test this, the same problem manifests itself with vertical bars, when clicking the x-labels.

Unless you have another idea this seems to be the end of the road for what I can do without changing the library itself.

@RoxKilly sorry about that. There is an error in the function the category scale uses to go backwards. I fixed it in #2870.

I updated your plunk with a hotpatch: http://plnkr.co/edit/GsOi2hX42389VJnuzGhv?p=preview
The patch is in app/main.ts

A typo on line 7 of your Plunk's app/main.ts file would cause an exception, so the bug remained. I changed

let ScaleConstructor = chart.scaleService...

With

let ScaleConstructor = Chart.scaleService...

by capitalizing the 'c' in "Chart". Initial testing is positive; the fix seems to work with both horizontal and vertical bar charts (the types I can confirm were not working before). Thanks again. Closing.

My bad on the typo. Hadn't had coffee yet :stuck_out_tongue:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lizbanach picture lizbanach  路  3Comments

gabrieldesouza picture gabrieldesouza  路  3Comments

JAIOMP picture JAIOMP  路  3Comments

nanospeck picture nanospeck  路  3Comments

joebirkin picture joebirkin  路  3Comments