Chart.js堆叠条形图 - 按值对条形进行排序

3
我尝试使用Chart.js框架(版本2.7)实现堆叠条形图,但遇到了以下问题:单个数据元素按照在JSON结构中提供的顺序绘制在每个条形图中(这是绝对合理和可理解的)。我希望它们能够排序:最大的元素在条形图底部,最小的元素在其顶部。

我认为可以使用一些插件自定义黑魔法来完成,但无法想出方法。

任何帮助将不胜感激。

示例:

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.7.2/Chart.bundle.min.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>

在这个例子中,我希望每一列中颜色的顺序相反: 第一列是蓝绿红, 第二列是红蓝绿或蓝红绿, 第三列是红绿蓝。
1个回答

3

也许有更高效和美观的方法,但我不得不自己解决这个问题。

/*
* 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>


1
非常感谢您提供这个。 - Naveed Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接