3

I'm trying to calculate the sum of the dataset values at the end of a tooltip in ChartJS.

When I execute this code in "label" callback, works correctly. However, when I execute this code in a different callback in "afterBody" or "footer" callback, it results in NaN.

new Chart(document.getElementById("line-chart"), {
                type: 'line',
                data: {
                    labels: [2018, 2019, 2020],
                    datasets: [{
                        data: [1.09, 1.48, 2.48],
                        label: "ABC",
                        borderColor: "#3e95cd",
                        fill: false
                    }, {
                        data: [0.63, 0.81, 0.95],
                        label: "DEF",
                        borderColor: "#8e5ea2",
                        fill: false
                    }, {
                        data: [0.17, 0.17, 0.18],
                        label: "GHI",
                        borderColor: "#3cba9f",
                        fill: false
                    }]
                },
                options: {
                    title: {
                        display: true,
                        text: 'Past 2FY + Current FY Estimate, US$ millions'
                    },
                    tooltips: {
                        mode: 'index',
                        callbacks: {
                            label: function(tooltipItem, data) {
                                if (tooltipItem.index > 0) {
                                    var previousdata = tooltipItem.index - 1;
                                    var growth = ", YoY: " + ((data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] / data.datasets[tooltipItem.datasetIndex].data[previousdata] * 100) - 100).toFixed(1) + "%";
                                } else {
                                    var growth = '';
                                };
                                
                                return data.datasets[tooltipItem.datasetIndex].label + ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + growth;
                                
                            },
                            afterBody: function(tooltipItem, data){
                                var total = 0;
                                for(var i=0; i < data.datasets.length; i++)
                                    total += data.datasets[i].data[tooltipItem.index];
                                return 'Sum:'+total;
                            }
                            }
                        }
                    }
                });
<canvas id="line-chart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>

Any help will be great!

I expect tooltip "Sum:" returns the sum of dataset values (in this case 'ABC' + 'CDE' + 'GHI' values).

Ricardo Costa
  • 47
  • 1
  • 6

1 Answers1

1

Your use case is the given example for tooltip callbacks on the Chart.js samples page with the following code:

// Use the footer callback to display the sum of the items showing in the tooltip
footer: function(tooltipItems, data) {
  var sum = 0;

  tooltipItems.forEach(function(tooltipItem) {
    sum += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
  });
  return 'Sum: ' + sum;
}

Editing your snippet as per the above example seems to yield the result you want, although you probably want it formatted to match the rest of your tooltip:

new Chart(document.getElementById("line-chart"), {
  type: 'line',
  data: {
    labels: [2018, 2019, 2020],
    datasets: [{
      data: [1.09, 1.48, 2.48],
      label: "ABC",
      borderColor: "#3e95cd",
      fill: false
    }, {
      data: [0.63, 0.81, 0.95],
      label: "DEF",
      borderColor: "#8e5ea2",
      fill: false
    }, {
      data: [0.17, 0.17, 0.18],
      label: "GHI",
      borderColor: "#3cba9f",
      fill: false
    }]
  },
  options: {
    title: {
      display: true,
      text: 'Past 2FY + Current FY Estimate, US$ millions'
    },
    tooltips: {
      mode: 'index',
      callbacks: {
        label: function(tooltipItem, data) {
          if (tooltipItem.index > 0) {
            var previousdata = tooltipItem.index - 1;
            var growth = ", YoY: " + ((data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] / data.datasets[tooltipItem.datasetIndex].data[previousdata] * 100) - 100).toFixed(1) + "%";
          } else {
            var growth = '';
          };

          return data.datasets[tooltipItem.datasetIndex].label + ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + growth;

        },
        footer: function(tooltipItems, data) {
          var sum = 0;

          tooltipItems.forEach(function(tooltipItem) {
            sum += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
          });
          return 'Sum: ' + sum;
        }
      }
    }
  }
});
<canvas id="line-chart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
timclutton
  • 12,682
  • 3
  • 33
  • 43
  • I've totally overlooked this example. It works, thanks a lot! By the way, not sure if it's a bug, but the first sum shows a large number as '1.890000000001'. The others are ok. To fix it, I changed the return clause to return 'Sum: ' + sum.toFixed(2); – Ricardo Costa Jul 22 '19 at 19:15
  • @RicardoCosta You're very welcome. It's not a bug in Chart.js if that's what you mean. Entering `1.09+.63+.17` in the web browser console will yield `1.8900000000000001` (at least for me in Firefox). This is because of [floating point precision](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) and how programming languages are designed to handle it. – timclutton Jul 22 '19 at 19:28
  • 1
    Oh, ok! It was funny to see it happening only for the first value, and not for the others (Chrome, in my case). Anyway, toFixed(2) solved that :-) – Ricardo Costa Jul 24 '19 at 12:29
  • Hi @timclutton, where did you see the snippet of the sample graph? When i click the two links you mentioned above I did not see such snippet. – AKJ Jun 02 '20 at 05:45
  • @AKJ View the page source of the first link. The second link is just to show all the available examples. – timclutton Jun 02 '20 at 05:49
  • @timclutton, i tried your solution above, but i still got this error, perhaps we hop over to my stackoverflow question? https://stackoverflow.com/questions/62145843/unable-to-produce-desired-ui-output-for-chartjs-tooltips – AKJ Jun 02 '20 at 06:09