Search code examples
javascriptchart.jsstacked-chart

Chart.js stacked bar chart in opposite direction


I am trying to achieve something like this using chart.js. I wanted to show data of male/female according to each age group:

Here is my chart options:

var options = {
    layout: {
        padding: {
            top: 5,
        }
    },
    scales:
    {
        yAxes: [{
            display: true,
            barPercentage: 0.4,
            ticks: {
                fontSize: 12
            },
            stacked: true,
        }],
        xAxes: [{
            stacked: true,
        }]
    },
    responsive: true,
    maintainAspectRatio: false,
    legend: {
        display: false,
    },
    animation: {
        animateScale: true,
        animateRotate: true
    },
};

var opt = {
    type: "horizontalBar",
    data: {
        labels: ageGroup,
        datasets: [{
            label: 'Male',
            data: maleData,
            backgroundColor: '#2196F3',
            hoverBackgroundColor: '#2196F3'
        },
        {
            label: 'Female',
            data: femaleData,
            backgroundColor: '#E91E63',
            hoverBackgroundColor: '#E91E63'
        }]
    },
    options: options
};

I changed the positive in femaleData array into a negative number to achieve the result above:

for (var i = 0; i < femaleData.length; i++) {
    femaleData[i] = -Math.abs(femaleData[i]);
}

However, the y-axis at 0 is not centralized as it pushed to the right hand side since left hand side got more data. I not even sure if this is the correct way to set the chart in opposite direction. How can I do this correctly?


Solution

  • as per the requirements mentioned in OP­'s comment section

    ꜱʜᴏᴡ ᴘᴏꜱɪᴛɪᴠᴇ ᴠᴀʟᴜᴇꜱ ᴏɴ x-ᴀxɪꜱ

    use the following callback function for x-axis ticks :

    callback: function(t, i) {
       return t < 0 ? Math.abs(t) : t;
    }
    

    ꜱʜᴏᴡ ᴘᴏꜱɪᴛɪᴠᴇ ᴠᴀʟᴜᴇ ᴏɴ ᴛᴏᴏʟᴛɪᴘ

    use the following callback function for tooltips :

    callbacks: {
       label: function(t, d) {
          var datasetLabel = d.datasets[t.datasetIndex].label;
          var xLabel = Math.abs(t.xLabel);
          return datasetLabel + ': ' + xLabel;
       }
    }
    

    ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩

    var ageGroup = ['0-10', '11-20', '21-30', '31-40', '41-50', '51-60', '61-70', '71-80', '80+'];
    var maleData = [30, 0, 0, 0, 10, 0, 0, 0, 0];
    var femaleData = [0, 0, 0, -20, -50, -20, 0, 0, 0];
    
    var options = {
       layout: {
          padding: {
             top: 5,
          }
       },
       scales: {
          yAxes: [{
             display: true,
             barPercentage: 0.4,
             ticks: {
                fontSize: 12
             },
             stacked: true,
          }],
          xAxes: [{
             stacked: true,
             ticks: {
                callback: function(t, i) {
                   return t < 0 ? Math.abs(t) : t;
                }
             }
          }]
       },
       tooltips: {
          callbacks: {
             label: function(t, d) {
                var datasetLabel = d.datasets[t.datasetIndex].label;
                var xLabel = Math.abs(t.xLabel);
                return datasetLabel + ': ' + xLabel;
             }
          }
       },
       responsive: true,
       //maintainAspectRatio: false,
       legend: {
          display: false,
       },
       animation: {
          animateScale: true,
          animateRotate: true
       },
    };
    
    var opt = {
       type: "horizontalBar",
       data: {
          labels: ageGroup,
          datasets: [{
             label: 'Male',
             data: maleData,
             backgroundColor: '#2196F3',
             hoverBackgroundColor: '#2196F3'
          }, {
             label: 'Female',
             data: femaleData,
             backgroundColor: '#E91E63',
             hoverBackgroundColor: '#E91E63'
          }]
       },
       options: options
    };
    
    new Chart(ctx, opt);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
    <canvas id="ctx"></canvas>