Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
488 views
in Technique[技术] by (71.8m points)

chart.js - How to order tooltip values from the biggest to the smallest

I use Chart.js and stack groups bar chart.

The problem is that I'd like to show the data from the biggest (higher) to the smallest (lower) to make it more readable.

Screenshot: enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...