简体   繁体   English

如何使用Charts.JS创建显示相对值而非绝对值的堆积条形图?

[英]How can I create a stacked bar chart with Charts.JS that displays relative rather than absolute values?

I am creating a stacked bar chart with Charts.JS that looks fairly good: 我正在使用Charts.JS创建一个看起来非常不错的堆积条形图:

在此处输入图片说明

What I need, though, is for each bar to completely fill the grid, and for the green value to be a percentage, not an absolute value, and for the red value in the same way to be 100% - whatever % the green value is. 不过,我需要的是每个条形图完全填充网格,绿色值是一个百分比,而不是绝对值,红色值以相同的方式是100%-无论绿色值是多少是。

IOW, for the values shown in the screenshot above, I need each bar to traverse the entire width and, using the top bar as an example, the text "labeled" onto the green portion should be "99%" IOW,对于上面的屏幕快照中显示的值,我需要每个条形图遍历整个宽度,以顶部条形图为例,绿色部分上的“标签”文本应为“ 99%”

The "99%" label should take the place of the "17,724", and the "170" should completely disappear. “ 99%”标签应代替“ 17,724”,而“ 170”应完全消失。

This is the data used currently: 这是当前使用的数据:

var priceComplianceData = {
    labels: [
        "Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce",
        "Get Fresh Sales",
        "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"
    ],
    datasets: [
    {
        label: "Price Compliant",
        backgroundColor: "rgba(34,139,34,0.5)",
        hoverBackgroundColor: "rgba(34,139,34,1)",
        data: [17724, 5565, 3806, 5925, 5721, 6635, 14080, 9027, 25553]
    },
    {
        label: "Non-Compliant",
        backgroundColor: "rgba(255, 0, 0, 0.5)",
        hoverBackgroundColor: "rgba(255, 0, 0, 1)",
        // The vals below have been multiplied by 10 (a 0 appended) so that the values are at least visible to the naked eye
        data: [170, 10, 180, 140, 30, 10, 50, 100, 10]
    }
    ]
}

...and then it's added to the chart like so: ...然后将其添加到图表中,如下所示:

var priceComplianceOptions = {
    scales: {
        xAxes: [
{
    stacked: true
}
        ],
        yAxes: [
{
    stacked: true
}
        ]
    },
    tooltips: {
        enabled: false
    }
};

var ctxBarChart = $("#priceComplianceBarChart").get(0).getContext("2d");
var priceBarChart = new Chart(ctxBarChart,
{
    type: 'horizontalBar',
    data: priceComplianceData,
    options: priceComplianceOptions
});

The thing that comes to mind is to change the data like so: 我想到的是像这样更改数据:

datasets: [
{
    label: "Price Compliant",
    backgroundColor: "rgba(34,139,34,0.5)",
    hoverBackgroundColor: "rgba(34,139,34,1)",
    data: [99.0, 99.2, 99.4, 98.9, 99.1, 99.5, 99.6, 99.2, 99.7]
},
{
    label: "Non-Compliant",
    backgroundColor: "rgba(255, 0, 0, 0.5)",
    hoverBackgroundColor: "rgba(255, 0, 0, 1)",
    data: [1.0, 0.8, 0.6, 1.1, 0.9, 0.5, 0.4, 0.8, 0.3]
}
]

...and then use the first data value as the one to label the green part with, appending a "%" to it. ...然后将第一个数据值用作标记​​绿色部分的值,并在其后附加“%”。

Is that a sensible approach? 这是明智的做法吗? Is there a better way? 有没有更好的办法?

UPDATE 更新

The proposed beforeInit/afterDraw doesn't work; 提议的beforeInit / afterDraw不起作用; causes my more-or-less acceptable charts: 导致我或多或少可以接受的图表:

在此处输入图片说明

...to get more hosed up than a haywire firehouse: ...比干草堆消防站更多

在此处输入图片说明

...even though I added this as the first line in both functions: ...即使我将其添加为两个函数的第一行:

if (chartInstance.id !== 1) return; 

Your idea is actually quite good, but as you declared in your question, it won't be dynamic and then won't work with every chart of this type. 您的想法实际上是相当不错的,但是正如您在问题中所声明的那样,它不会是动态的,因此不适用于该类型的每个图表。

A way to make it dynamic is to use Chart.js plugins where the beforeInit event will be handled to edit the data to fit your percentage problem, and where the afterDraw event will be handled to write the percentage over the bar : 使它动态化的一种方法是使用Chart.js插件 ,其中将处理beforeInit事件以编辑数据以适合您的百分比问题,并在其中afterDraw事件将被处理以将百分比写在条形上:

Chart.pluginService.register({

    // This event helps to edit the data in our datasets to fit a percentage scale
    beforeInit: function(chartInstance) {

        // We first get the total of datasets for every data
        var totals = [];
        chartInstance.data.datasets.forEach(function(dataset) {
            for (var i = 0; i < dataset.data.length; i++) {
                var total = 0;
                chartInstance.data.datasets.forEach(function(dataset) {
                    total += dataset.data[i];
                });
                totals.push(total);
            }
        });

        // And use it to calculate the percentage of the current data
        chartInstance.data.datasets.forEach(function(dataset) {
            for (var i = 0; i < dataset.data.length; i++) {
                // This ----------¬     is useful to add it as a string in the dataset
                // It solves      V      the problem of values with `.0` at decimals
                dataset.data[i] = '' + (dataset.data[i] / totals[i]) * 100;
            }
        });
    },

    // This event allows us to add the percentage on the bar
    afterDraw: function(chartInstance) {

        // We get the canvas context
        var ctx = chartInstance.chart.ctx;

        // And set the properties we need
        ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign = 'center';
        ctx.textBaseline = 'bottom';
        ctx.fillStyle = '#666';

        // For every dataset ...
        chartInstance.data.datasets.forEach(function(dataset) {

            // If it is not the first dataset, we return now (no action)
            if (dataset._meta[0].controller.index != 0) return;

            // For ervery data in the dataset ...
            for (var i = 0; i < dataset.data.length; i++) {

                // We get the model of the data
                var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;

                // And use it to display the text where we want
                ctx.fillText(parseFloat(dataset.data[i]).toFixed(2) + "%", ((model.base + model.x) / 2), (model.y + model.height / 3));
            }
        });
    }
});


You can see this code working on this jsFiddle and here is its result : 您可以看到此代码在此jsFiddle上运行 ,其结果如下:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM