Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embed unique identifier in Chart.js segments?

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?

like image 422
SAyotte Avatar asked Feb 07 '15 00:02

SAyotte


2 Answers

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>
like image 52
Quince Avatar answered Nov 06 '22 22:11

Quince


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'];
    }
  } 
like image 2
Ronald Dsouza Avatar answered Nov 06 '22 22:11

Ronald Dsouza