2

Can I offset the bars in the chart.js stacked bar chart like so: enter image description here

  • 1
    As far as I know: No, you can't.. the ones in their [samples' page](https://www.chartjs.org/samples/latest/) are the only thing you can do – Soul Eater Dec 31 '19 at 16:38

2 Answers2

3

Based on this answer, I created a runnable code snippet that illustrates how it could be done. I'm not using stacked bars because the use case is not clear to me and the image from the question rather looks like a bar with shadows.

const dataset = [40, 80, 50, 60, 70];
const offset = 8;

Chart.pluginService.register({
    afterUpdate: function(chart) {
        var dataset = chart.config.data.datasets[1];
        for (var i = 0; i < dataset._meta[0].data.length; i++) {
            var model = dataset._meta[0].data[i]._model;
            model.x += offset;
            model.controlPointNextX += offset;
            model.controlPointPreviousX += offset;
        }
    }
});

var data = {
    labels: ["A", "B", "C", "D", "E"],
    datasets: [{
            backgroundColor: [
              'rgba(255, 99, 132)',
              'rgba(255, 206, 86)',
              'rgba(54, 162, 235)',              
              'rgba(75, 192, 192)',
              'rgba(153, 102, 255)'
              ],
            borderWidth: 1,
            data: dataset,
            xAxisID: "bar-x-axis1",
            categoryPercentage: 0.5,
            barPercentage: 0.5,
        },
        {
            backgroundColor: 'rgba(0, 0, 0, 0.2)',
            data: dataset.map(v => v + offset),
            xAxisID: "bar-x-axis2",
            categoryPercentage: 0.5,
            barPercentage: 0.5
        }
    ]
};

var options = {  
    legend: {
        display: false
    },
    tooltips: {
        enabled: false
    },
    scales: {        
        xAxes: [
            {
                id: "bar-x-axis2"
            },
            {
                id: "bar-x-axis1",              
                offset: true,
                ticks: {
                   display: false
                }
           }
        ],
        yAxes: [{
            id: "bar-y-axis1",
            ticks: {
                beginAtZero: true,
                stepSize: 50
            }
        }]
    }
};

var ctx = document.getElementById("myChart").getContext("2d");
var myBarChart = new Chart(ctx, {
    type: 'bar',
    data: data,
    options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="60"></canvas>
uminder
  • 23,831
  • 5
  • 37
  • 72
  • wow, thanks. I already implemented this functionality without chart.js just using plain html using divs to create rectangles to representing the bars. – Rolandas Burbulis Jan 17 '20 at 15:18
  • @uminder It seems like _,meta has been removed. Any chance you have a new solution for chart.js v3? – Arib Mar 09 '22 at 07:05
  • 1
    @Arib: I posted another answer that illustrates how to solve the problem with Chart.js v3: https://stackoverflow.com/a/71410608/2358409 – uminder Mar 09 '22 at 14:06
1

For Chart.js v3, you can use a different approach.

  1. In the beforeDatasetsDraw, you save the define the shadow properties on the canvas through CanvasRenderingContext2D. Make sure to first save the state of the rendering context by invoking ctx.save().
  2. In the afterDatasetsDraw hook, you need to restore the state of the rendering context by invoking ctx.restore().
  3. Convert the bars into floating bars through data: data.map(v => [-20, v]) to makes sure, the shadows appear from the base of the bars.
  4. Define a tooltip.callbacks.label function that provides the initial values in the tooltips.

Please take a look at below runnable code and see how it works.

const data = [40, 80, 50, 60, 70];
const offset = 10;

new Chart('myChart', {
  type: 'bar',
  plugins: [{
    beforeDatasetsDraw: chart => {
      const ctx = chart.ctx;
      ctx.save();
      ctx.shadowOffsetX = offset;
      ctx.shadowOffsetY = -offset;
      ctx.shadowBlur = 5;
      ctx.shadowColor = 'rgb(220, 220, 220)';
    },
    afterDatasetsDraw: chart => chart.ctx.restore()
  }],
  data: {
    labels: ["A", "B", "C", "D", "E"],
    datasets: [{
      label: 'My Data',
      data: data.map(v => [-20, v]),
      backgroundColor: [
        'rgba(255, 99, 132)',
        'rgba(255, 206, 86)',
        'rgba(54, 162, 235)',
        'rgba(75, 192, 192)',
        'rgba(153, 102, 255)'
      ],
      categoryPercentage: 0.8
    }]
  },
  options: {
    plugins: {
      tooltip: {
        callbacks: {
          label: ctx => data[ctx.dataIndex]
        }
      }
    },
    scales: {
      y: {
        min: 0,
        max: Math.max(...data) + offset
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>
uminder
  • 23,831
  • 5
  • 37
  • 72