Chartjs-How to order tooltip values from the biggest to the smallest

1👍

In Chart JS 3.4.1 you have the tooltip.itemSort option. I suspect you have a stacked bar chart. So this will work fine for ASC (lowest to highest) or DESC (highest to lowest) order of the tooltip.

That is the one you can use to sort the tooltip without too much hassle. I have added a complete video covering this topic as well which explains the process in depth: how to sort tooltip in Chart JS.

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  // setup 
  const labels = ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'];
  const datapoint = [12, 19, 3, 5, 2, 3];
  const backgroundColor = ['rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)'];
  const borderColor = ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)'];

  const labels2 = ['green', 'blue', 'black', 'brown', 'purple', 'pink'];
  const datapoint2 = [3, 7, 13, 9, 8, 13];
  const backgroundColor2 = ['green', 'blue', 'black', 'brown', 'purple', 'pink'];
  const borderColor2 = ['green', 'blue', 'black', 'brown', 'purple', 'pink'];

  const data = {
    labels: labels,
    datasets: [{
      label: '# of Votes',
      data: datapoint,
      backgroundColor: backgroundColor,
      borderColor: borderColor,
      borderWidth: 1
    }, {
      label: '# of Sales',
      data: datapoint2,
      backgroundColor: backgroundColor2,
      borderColor: borderColor2,
      borderWidth: 1
    }]
  };

  // config 
  const config = {
    type: 'bar',
    data,
    options: {
      plugins: {
        tooltip: {
          itemSort: function (a, b) {
            return b.raw - a.raw;
          }
        }
      },
      scales: {
        x: {
          stacked: true
        },
        y: {
          stacked: true,
          beginAtZero: true
        }
      }
    }
  };

  // render init block
  const myChart = new Chart(
    document.getElementById('myChart'),
    config
  );
</script>

0👍

Use external tooltips, in the var bodyLines from the example are the items of the tooltip, if you process the array beforehand that it is sorted correctly you will have a sorted tooltip:
https://www.chartjs.org/docs/latest/configuration/tooltip.html#external-custom-tooltips

Using external tooltip as base from chartjs samples:

Chart.defaults.pointHitDetectionRadius = 1;

    var getOrCreateTooltip = function(chart) {
        var tooltipEl = chart.canvas.parentNode.querySelector('div');

        if (!tooltipEl) {
            tooltipEl = document.createElement('div');
            tooltipEl.classList.add('chartjs-tooltip');
            tooltipEl.innerHTML = '<table></table>';
            chart.canvas.parentNode.appendChild(tooltipEl);
        }

        return tooltipEl;
    };

    var customTooltips = function(context) {
        // Tooltip Element
        var chart = context.chart;
        var tooltipEl = getOrCreateTooltip(chart);

        // Hide if no tooltip
        var tooltip = context.tooltip;
        if (tooltip.opacity === 0) {
            tooltipEl.style.opacity = 0;
            return;
        }

        // Set caret Position
        tooltipEl.classList.remove('above', 'below', 'no-transform');
        if (tooltip.yAlign) {
            tooltipEl.classList.add(tooltip.yAlign);
        } else {
            tooltipEl.classList.add('no-transform');
        }

        function getBody(bodyItem) {
            return bodyItem.lines;
        }

        // Set Text
        if (tooltip.body) {
            var titleLines = tooltip.title || [];
            var bodyLines = tooltip.body.map(getBody);
            
            // make object by parsing the last number with regex (the value) and then sort it, add index to it for color later on
            var objectBodyLines = bodyLines.map((input, index) => ({number: /(\d+)(?!.*\d)/.exec(input)[0], whole: input[0], index})).sort((a,b) => {return (a.number > b.number) ? 1 : ((b.number > a.number) ? -1 : 0)});

            var innerHtml = '<thead>';

            titleLines.forEach(function(title) {
                innerHtml += '<tr><th>' + title + '</th></tr>';
            });
            innerHtml += '</thead><tbody>';

            objectBodyLines.forEach(function(body, i) {
                var colors = tooltip.labelColors[body.index];
                var style = 'background:' + colors.backgroundColor;
                style += '; border-color:' + colors.borderColor;
                style += '; border-width: 2px';
                var span = '<span class="chartjs-tooltip-key" style="' + style + '"></span>';
                innerHtml += '<tr><td>' + span + body.whole + '</td></tr>';
            });
            innerHtml += '</tbody>';

            var tableRoot = tooltipEl.querySelector('table');
            tableRoot.innerHTML = innerHtml;
        }

        var positionY = chart.canvas.offsetTop;
        var positionX = chart.canvas.offsetLeft;

        // Display, position, and set styles for font
        tooltipEl.style.opacity = 1;
        tooltipEl.style.left = positionX + tooltip.caretX + 'px';
        tooltipEl.style.top = positionY + tooltip.caretY + 'px';
        tooltipEl.style.font = tooltip.options.bodyFont.string;
        tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
    };

    var lineChartData = {
        labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
        datasets: [{
            label: 'My First dataset',
            borderColor: window.chartColors.red,
            pointBackgroundColor: window.chartColors.red,
            fill: false,
            data: [
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor()
            ]
        }, {
            label: 'My Second dataset',
            borderColor: window.chartColors.blue,
            pointBackgroundColor: window.chartColors.blue,
            fill: false,
            data: [
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor(),
                randomScalingFactor()
            ]
        }]
    };

    window.onload = function() {
        var chartEl = document.getElementById('chart');
        window.myLine = new Chart(chartEl, {
            type: 'line',
            data: lineChartData,
            options: {
                plugins: {
                    title: {
                        display: true,
                        text: 'Chart.js Line Chart - Custom Tooltips'
                    },
                    tooltip: {
                        enabled: false,
                        mode: 'index',
                        intersect: false,
                        position: 'nearest',
                        custom: customTooltips
                    }
                }
            }
        });
    };

Only adjustments I made is transform the bodylines into a new array with info I could use (can do this also straigt on the bodylines var), in the objectBodyLines.forEach loop pick the right part from my object to fill the tooltip and set the color.

After quick extra test its not totally working, guess I made a mistake somewhere in the sort I guess but it should still give you a good starting point to work from

Leave a comment