0
votes

I'm creating a Chart.js bar chart like so:

HTML

<canvas id="priceComplianceBarChart" width="540" height="360"></canvas>

JQUERY

var barChartData = {
    labels: ["Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce", "Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"],
    datasets: [
        {
            fillColor: "rgba(220,220,220,0.5)",
            strokeColor: "rgba(220,220,220,0.8)",
            highlightFill: "rgba(220,220,220,0.75)",
            highlightStroke: "rgba(220,220,220,1)",
            data: [17724, 5565, 3806, 5925, 5721, 6635, 14080, 9027, 25553]
        },
        {
            fillColor: "rgba(151,187,205,0.5)",
            strokeColor: "rgba(151,187,205,0.8)",
            highlightFill: "rgba(151,187,205,0.75)",
            highlightStroke: "rgba(151,187,205,1)",
            data: [17, 1, 18, 14, 3, 1, 5, 10, 1]
        }
    ]
}

var ctxBarChart = document.getElementById("priceComplianceBarChart").getContext("2d");
var myBarChart = new Chart(ctxBarChart).Bar(barChartData);

That produces a chart that looks like this:

enter image description here

What I want instead, though, is the two side-by-side values to appear stacked onto the same bar, in different colors, and then a calculated value (% of the total which is represented by the predominant color) to be added as a label on each bar and appended to the legends, too (such as, "Bix Produce - 99.9%").

The appending of the val to the legend labels below the bars I can figure out myself, I'm sure, but how to stack the two values onto one bar, and how to add the label to the bars - I have no idea how to accomplish those objectives.

UPDATE

I'm trying Sergiu M's code, but must be doing something wrong, because my div in which the chart should appear is now completely blank. Here is my new code:

HTML

<div class="topright">
    <h2 class="sectiontext">Price Compliance</h2>
    <div class="graph_container">
        <canvas id="priceComplianceBarChart" width="400" height="400"></canvas>
    </div>
</div>

CSS

.topright {
    margin-top: -4px;
    margin-right: 16px;
    margin-bottom: 16px;
    margin-left: -12px;
    padding: 16px;
    border: 1px solid black;
}

.sectiontext {
    font-size: 1.5em;
    font-weight: bold;
    font-family: Candara, Calibri, Cambria, serif;
    color: green;
    margin-top: -4px;
}

JQUERY

var ctxBarChart = document.getElementById("priceComplianceBarChart").getContext("2d");
var priceBarChart = new Chart(ctxBarChart, {
    type: 'bar',
    data: {
        labels: ["Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce", "Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"],
        datasets: [{
            label: 'Some Values',
            backgroundColor: 'rgba(97, 188, 109, 0.2)',
            borderColor: 'rgba(97, 188, 109, .8)',
            data: [7000, 5565, 3806, 5925, 5721, 6635, 14080, 9027, 25553]
            //data: [17724, 2565, 1506, 3625, 3721, 4635, 7080, 4027, 12553]
        }, {
            label: 'Other Values',
            backgroundColor: 'rgba(236, 107, 86, 0.2)',
            borderColor: 'rgba(236, 107, 86, .8)',
            data: [17724, 2565, 1506, 3625, 3721, 4635, 7080, 4027, 12553]
            //data: [17, 1, 18, 14, 3, 1, 5, 10, 1]
        }]
    },
    options: {
        tooltips: {
            enabled: false
        },
        animation: {
            duration: 0,
            onComplete: function () {
                if (this.data.datasets.length === 2) {
                    // render the value of the chart above the bar
                    var ctx = this.chart.ctx;
                    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
                    ctx.fillStyle = this.chart.config.options.defaultFontColor;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'bottom';
                    var firstDataSet = this.data.datasets[0];
                    var secondDataSet = this.data.datasets[1];
                    if (firstDataSet.length === secondDataSet.length) {
                        for (var i = 0; i < firstDataSet.data.length; i++) {
                            var firstModel = firstDataSet._meta[Object.keys(firstDataSet._meta)[0]].data[i]._model;
                            var secondModel = secondDataSet._meta[Object.keys(secondDataSet._meta)[0]].data[i]._model;
                            var total = firstDataSet.data[i] + secondDataSet.data[i];
                            if (firstDataSet.data[i] >= secondDataSet.data[i]) {
                                ctx.fillText((firstDataSet.data[i] * 100 / total).toFixed(2) + '%', firstModel.x, firstModel.y + 30);
                            } else {
                                ctx.fillText((secondDataSet.data[i] * 100 / total).toFixed(2) + '%', secondModel.x, secondModel.y + 30);
                            }
                        }
                    }
                }
            }
        },
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                },
                stacked: true
            }],
            xAxes: [{
                stacked: true,
            }]
        }
    }
});
1
perhaps this github issue can help you github.com/chartjs/Chart.js/issues/10Ronnie
Can you give example some example of how you want to display your chart. Can you add screenshot for final outputAbhijeet
@Abhijeet: I don't have an image of what it should look like; it's simply one rectange of data stacked on another rectangle of data (a "stacked bar chart") with the % value printed as a label in the larger block. e.g., if the total was 1,000, and the larger block was 900, the % label would be "90%"B. Clay Shannon

1 Answers

3
votes

in order to achieve a stacked bar chart with chart js you can use this code http://codepen.io/anon/pen/ozzyJy. I have replaced the second data values array with some bigger values in order to illustrate the stacked bars, but it will work fine with any values:

var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce", "Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"],
        datasets: [{
            backgroundColor: 'rgba(97, 188, 109, 0.2)',
            borderColor: 'rgba(97, 188, 109, .8)',
            data: [7000, 5565, 3806, 5925, 5721, 6635, 14080, 9027, 25553]
        }, {
            backgroundColor: 'rgba(236, 107, 86, 0.2)',
            borderColor: 'rgba(236, 107, 86, .8)',
            data: [17724, 2565, 1506, 3625, 3721, 4635, 7080, 4027, 12553]
            //data: [17, 1, 18, 14, 3, 1, 5, 10, 1]
        }]
    },
    options: {
        tooltips: {
            enabled: false
        },
        animation: {
            duration: 0,
            onComplete: function() {
                if (this.data.datasets.length === 2) {
                    var ctx = this.chart.ctx;
                    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
                    ctx.fillStyle = this.chart.config.options.defaultFontColor;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'bottom';
                    var firstDataSet = this.data.datasets[0];
                    var secondDataSet = this.data.datasets[1];
                    if (firstDataSet.length === secondDataSet.length) {
                        for (var i = 0; i < firstDataSet.data.length; i++) {
                            var firstModel = firstDataSet._meta[Object.keys(firstDataSet._meta)[0]].data[i]._model;
                            var secondModel = secondDataSet._meta[Object.keys(secondDataSet._meta)[0]].data[i]._model;
                            var total = firstDataSet.data[i] + secondDataSet.data[i];
                            if (firstDataSet.data[i] >= secondDataSet.data[i]) {
                                ctx.fillText((firstDataSet.data[i] * 100 / total).toFixed(2) + '%', firstModel.x, firstModel.y + 30);
                            }else{
                                ctx.fillText((secondDataSet.data[i] * 100 / total).toFixed(2) + '%', secondModel.x, secondModel.y + 30);
                            }
                        }
                    }
                }
            }
        },
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                },
                stacked: true
            }],
            xAxes: [{
                stacked: true,
            }]
        }
    }
 });