I want to make my pie-chart interactive by allowing the user to double-click on a slice to drill down. I believe that the way to do this is to create an onclick handler on the canvas, and use getSegmentsAtEvent()
to determine which slice was clicked.
The segment data returned by the call to getSegmentsAtEvent()
is possibly ambiguous though. Here is a sample of the returned data:
[{
"circumference": 4.1887902047863905,
"endAngle": 8.901179185171081,
"fillColor": "#FF5A5E",
"highlightColor": "#FF5A5E",
"innerRadius": 0,
"label": "Red",
"outerRadius": 99.5,
"showStroke": true,
"startAngle": 4.71238898038469,
"strokeColor": "#fff",
"strokeWidth": 2,
"value": 300
}]
Of those fields, only value
, fillColor
, highlightColor
, and label
are supplied by me, and none of them are necessarily unique. I could ensure that label
is unique, but that might make it less readable for humans.
I have tried adding an additional property (e.g. "id") into the data I pass into Pie()
, but it is stripped out when I get the segment data back from this call. Is there a way to add a property to each segment which I can use to positively identify them, without overloading the label
field?
You would need to either override the pie chart or create a new chart type that inherits from pie.
Here is an example of a new chart type, i have passed a new attribute called id and then the only thing that needs to be different in this chart is that when the data is being added this id needs to passed to the chart
Chart.types.Pie.extend({
name: "PieUnique",
addData: function (segment, atIndex, silent) {
var index = atIndex || this.segments.length;
this.segments.splice(index, 0, new this.SegmentArc({
value: segment.value,
outerRadius: (this.options.animateScale) ? 0 : this.outerRadius,
innerRadius: (this.options.animateScale) ? 0 : (this.outerRadius / 100) * this.options.percentageInnerCutout,
fillColor: segment.color,
highlightColor: segment.highlight || segment.color,
showStroke: this.options.segmentShowStroke,
strokeWidth: this.options.segmentStrokeWidth,
strokeColor: this.options.segmentStrokeColor,
startAngle: Math.PI * this.options.startAngle,
circumference: (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
label: segment.label,
//add option passed
id: segment.id
}));
if (!silent) {
this.reflow();
this.update();
}
},
});
var pieData = [{
value: 300,
color: "#F7464A",
highlight: "#FF5A5E",
label: "Red",
id: "1-upi"
}, {
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green",
id: "2-upi"
}, {
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow",
id: "3-upi"
}, {
value: 40,
color: "#949FB1",
highlight: "#A8B3C5",
label: "Grey",
id: "4-upi"
}, {
value: 120,
color: "#4D5360",
highlight: "#616774",
label: "Dark Grey",
id: "5-upi"
}
];
var ctx = document.getElementById("chart-area").getContext("2d");
window.myPie = new Chart(ctx).PieUnique(pieData);
document.getElementById("chart-area").onclick = function (evt) {
var activePoints = window.myPie.getSegmentsAtEvent(evt);
//you can now access the id at activePoints[0].id
console.log(activePoints);
};
<script src="https://raw.githack.com/leighquince/Chart.js/master/Chart.js"></script>
<canvas id="chart-area" width="400"></canvas>
To get an slice that was clicked on, getElementAtEvent can be used. Worked for me!
stackedBar(datasets) {
var c = $("#canvas-bar");
var ctx = c[0].getContext("2d");
let __this = this;
this.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["something"],
datasets: datasets,
},
options: {
onClick: function (e, item) {
__this.onClickAction(e, item);
},
title: {},
legend: {},
scales: {}
}
});
}
onClickAction(event, elements) {
if (elements && elements.length) {
let selected = this.chart.getElementAtEvent(event)[0];
let sliceIndex = selected['_datasetIndex'];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With