How to add OnClick event to shortcuts in Chart.js v2.0?

Looking for a method to add the onClick handle of the "label" element in chartjs 2.0 since using the method below returns "unifined" in console.log whenever you click on any of the label attributes in Char.js V2.0 RadarChart.

var data = { // below line is the labels labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"], datasets: [ { label: "My First dataset", //this only shows as legend, not label. backgroundColor: "rgba(179,181,198,0.2)", borderColor: "rgba(179,181,198,1)", pointBackgroundColor: "rgba(179,181,198,1)", pointBorderColor: "#fff", pointHoverBackgroundColor: "#fff", pointHoverBorderColor: "rgba(179,181,198,1)", data: [65, 59, 90, 81, 56, 55, 40] }, .... 

 //Below is how to OnClick on chart points in chart.js V2, //However, it didn't apply to labels, will return "undifined" . $('#ChartV2').click(function(e) { var activePoints = myRadarChart.getElementsAtEvent(e); var firstPoint = activePoints[0]; console.log(firstPoint); if (firstPoint !== undefined){ alert(firstPoint._index); } }); 
+6
source share
3 answers

getElementsAtEvent checks only the main elements of the chart (bars, points, sectors ...). If you also want to consider labels, you will have to redefine the functionality for labels.

Most of the necessary code is already available in different methods in the code of the Chart.js library. Just copy / paste / clear as below.


Script

Your clicker should be

 $('#myChart').click(function (e) { var helpers = Chart.helpers; var eventPosition = helpers.getRelativePosition(e, myRadarChart.chart); var mouseX = eventPosition.x; var mouseY = eventPosition.y; var activePoints = []; // loop through all the labels helpers.each(myRadarChart.scale.ticks, function (label, index) { for (var i = this.getValueCount() - 1; i >= 0; i--) { // here we effectively get the bounding box for each label var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5); var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize); var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle); var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily); var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily); ctx.font = pointLabeFont; var labelsCount = this.pointLabels.length, halfLabelsCount = this.pointLabels.length / 2, quarterLabelsCount = halfLabelsCount / 2, upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount), exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount); var width = ctx.measureText(this.pointLabels[i]).width; var height = pointLabelFontSize; var x, y; if (i === 0 || i === halfLabelsCount) x = pointLabelPosition.x - width / 2; else if (i < halfLabelsCount) x = pointLabelPosition.x; else x = pointLabelPosition.x - width; if (exactQuarter) y = pointLabelPosition.y - height / 2; else if (upperHalf) y = pointLabelPosition.y - height; else y = pointLabelPosition.y // check if the click was within the bounding box if ((mouseY >= y && mouseY <= y + height) && (mouseX >= x && mouseX <= x + width)) activePoints.push({ index: i, label: this.pointLabels[i] }); } }, myRadarChart.scale); var firstPoint = activePoints[0]; if (firstPoint !== undefined) { alert(firstPoint.index + ': ' + firstPoint.label); } }); 

Fiddle - http://jsfiddle.net/1Lngmtz7/

+7
source

in chart.js 2.5 (maybe even earlier) you can put onClick in the parameters:

 'legend' : { 'onClick' : function (evt, item) { console.log ('legend onClick', evt, item); }, 'display' : true, 'labels' : ... 
+9
source

I found a solution for this for version 2.8.0 by copying the label position calculations from the RadialLinear scale into an event handler.

 document.getElementById("myChart").onclick = function (e) { var helpers = Chart.helpers; var scale = myRadarChart.scale; var opts = scale.options; var tickOpts = opts.ticks; // Position of click relative to canvas. var mouseX = e.offsetX; var mouseY = e.offsetY; var labelPadding = 5; // number pixels to expand label bounding box by // get the label render position // calcs taken from drawPointLabels() in scale.radialLinear.js var tickBackdropHeight = (tickOpts.display && opts.display) ? helpers.valueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize) + 5: 0; var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); for (var i = 0; i < scale.pointLabels.length; i++) { // Extra spacing for top value due to axis labels var extra = (i === 0 ? tickBackdropHeight / 2 : 0); var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5); // get label size info. // TODO fix width=0 calc in Brave? // https://github.com/brave/brave-browser/issues/1738 var plSize = scale._pointLabelSizes[i]; // get label textAlign info var angleRadians = scale.getIndexAngle(i); var angle = helpers.toDegrees(angleRadians); var textAlign = 'right'; if (angle == 0 || angle == 180) { textAlign = 'center'; } else if (angle < 180) { textAlign = 'left'; } // get label vertical offset info // also from drawPointLabels() calcs var verticalTextOffset = 0; if (angle === 90 || angle === 270) { verticalTextOffset = plSize.h / 2; } else if (angle > 270 || angle < 90) { verticalTextOffset = plSize.h; } // Calculate bounding box based on textAlign var labelTop = pointLabelPosition.y - verticalTextOffset - labelPadding; var labelHeight = 2*labelPadding + plSize.h; var labelBottom = labelTop + labelHeight; var labelWidth = plSize.w + 2*labelPadding; var labelLeft; switch (textAlign) { case 'center': var labelLeft = pointLabelPosition.x - labelWidth/2; break; case 'left': var labelLeft = pointLabelPosition.x - labelPadding; break; case 'right': var labelLeft = pointLabelPosition.x - labelWidth + labelPadding; break; default: console.log('ERROR: unknown textAlign '+textAlign); } var labelRight = labelLeft + labelWidth; // Render a rectangle for testing purposes ctx.save(); ctx.strokeStyle = 'red'; ctx.lineWidth = 1; ctx.strokeRect(labelLeft, labelTop, labelWidth, labelHeight); ctx.restore(); // compare to the current click if (mouseX >= labelLeft && mouseX <= labelRight && mouseY <= labelBottom && mouseY >= labelTop) { alert(scale.pointLabels[i]+' clicked'); // Break loop to prevent multiple clicks, if they overlap we take the first one. break; } } }; 

JSFiddle here:

https://jsfiddle.net/simoncoggins/7r08uLk9/

The disadvantage of this approach is that it will break if the implementation of the basic labeling changes in the future. It would be better if the library separated the calculation of the position of the label from its rendering and began to expose position information through the API. Then this solution can be greatly simplified and more resistant to changes in the library.

I opened a ticket offer here:

https://github.com/chartjs/Chart.js/issues/6549

Please comment on this question if you find it useful.

+1
source

All Articles