Chart.js stacked bar chart - sorting values in bar by value

后端 未结 1 823
一个人的身影
一个人的身影 2021-01-07 15:12

I try to implement a stacked bar chart using Chart.js framework (version 2.7) und faced following problem: single data elements are drawn in each bar in the same order as pr

相关标签:
1条回答
  • Probably it could be done somehow more efficient and / or beautiful, but I had to solve it on my own.

    /*
    * chart.js do not support stacked bar charts, which are sorted by value,
    * therefore it's needed to perform this functionality with custom plugins
    */
    Chart.plugins.register({
    
    /*
    * Sorts data by value and calculates values for bar stacks
    */
    beforeDraw(chart) {
    
        // create data container in chart instance
        chart.sortedData = {};
        
        // iterate over datasets
        chart.data.datasets.forEach((dataset, datasetIndex) => {
        
            // iterate over dataset records
            dataset.data.forEach((data, index) => {
            
                // create data container for bar stack data
                if(!chart.sortedData[index]) {
                    chart.sortedData[index] = {
                        data: []
                    };
                }
                
                // save data
                chart.sortedData[index].data[datasetIndex] = {
                    datasetIndex: datasetIndex,
                    hidden: chart.getDatasetMeta(datasetIndex).hidden ? true : false,
                    color: dataset.backgroundColor,
                    value: dataset.data[index].y,
                    y: chart.getDatasetMeta(datasetIndex).data[index]._model.y,
                    base: chart.getDatasetMeta(datasetIndex).data[index]._model.base,
                };
                
            });
        });
        
        var chartTop = chart.scales['y-axis-0'].top;
        var max = chart.scales['y-axis-0'].max;
        var h = chart.scales['y-axis-0'].height / max;
        
        // iterate over datasets
        chart.data.datasets.forEach((dataset, datasetIndex) => {
            
            // iterate over dataset records
            dataset.data.forEach((data, index) => {
            
                // sort data in bar stack by value
                chart.sortedData[index].data = Object.keys(chart.sortedData[index].data)
                    .map(k => chart.sortedData[index].data[k])
                    .sort((a, b) => a.value - b.value);
                    
                // iterate over stack records
                chart.sortedData[index].data.forEach((d, i) => {
                
                    // calculate base value
                    d.base = chartTop + (max - Object.keys(chart.sortedData[index].data)
                        .map(k => chart.sortedData[index].data[k].value)
                        .reduce((a, b) => a + b, 0)) * h
                        + Object.keys(chart.sortedData[index].data)
                        .map(k => chart.sortedData[index].data[k])
                        .filter(d => d.hidden)
                        .reduce((a, b) => a + b.value, 0) * h;                  
                    
                    // increase base value with values of previous records
                    for (var j = 0; j < i; j++) {
                        d.base += chart.sortedData[index].data[j].hidden 
                            ? 0 
                            : h * chart.sortedData[index].data[j].value;
                    }
                    
                    // set y value
                    d.y = d.base + h * d.value;
                    
                });
            });
        });
    },
    
    /*
    * Sets values for base and y
    */
    beforeDatasetDraw(chart, args) {
        chart.getDatasetMeta(args.index).data.forEach((data, index) => {
            var el = chart.sortedData[index].data.filter(e => e.datasetIndex === args.index)[0];
            data._model.y = el.y;
            data._model.base = el.base;
        });
       }
       
    });
    
    var chart = new Chart(document.getElementById('canvas'), {
                    type : 'bar',
                    data : {
                        labels : ["2018-07-06", "2018-07-07", "2018-07-08", "2018-07-09", "2018-07-10"],
                        datasets : [
                            {
                                label: "Dataset 1", 
                                backgroundColor: "red", 
                                data: [ {x: "2018-07-06", y: 1}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 3}]
                            }, 
                            {
                                label: "Dataset 2", 
                                backgroundColor: "blue", 
                                data: [ {x: "2018-07-06", y: 3}, {x: "2018-07-07", y: 2}, {x: "2018-07-08", y: 1}]
                            }, 
                            {
                                label: "Dataset 3", 
                                backgroundColor: "green", 
                                data: [ {x: "2018-07-06", y: 2}, {x: "2018-07-07", y: 1}, {x: "2018-07-08", y: 2}]
                            }
                        ],
                        borderWidth : 1
                    },
                    options : {
                        responsive : true,
                        maintainAspectRatio : false,
                        title : {
                            display : true,
                            text : 'Test'
                        },
                        scales : {
                            xAxes : [ {
                                stacked : true,
                                time : {
                                    unit : 'day'
                                }
                            } ],
                            yAxes : [ {
                                stacked : true,
                                ticks : {
                                    beginAtZero : true
                                }
                            } ]
                        }
                    }
                });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
    <canvas id="canvas" height="500" width="500"></canvas>

    0 讨论(0)
提交回复
热议问题