Antony
Antony

Reputation: 4300

Horizontal overlapping of bars, not whole graph

Bar chart with overlapping bars

I have been asked to create a bar graph similar to the above and I want to know if it is possible within chart.js?? I have had a look at a number of sites (such as Overlapping Bar Chart using Chart.js and https://github.com/chartjs/Chart.js/issues/5224) but the idea there is to have two graphs behind each other directly - I need to be able to set the position of the blocks (i.e. almost go something like margin-left:-5px as I would in CSS) - or at least have some overlap (or about 40% overlap). If not I might have to build it in CSS but it would be great to use Chart JS.

Upvotes: 0

Views: 1711

Answers (1)

uminder
uminder

Reputation: 26150

The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the afterUpdate hook to shift the bars of individual datasets by the desired number of pixels as follows:

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

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

const offset = 12;

new Chart('myChart', {
  type: 'bar',
  plugins: [{
    afterUpdate: function(chart) {
      let datasets = chart.config.data.datasets;
      for (let iDs = 1; iDs < datasets.length; iDs++) {
        let dataset = datasets[iDs];
        for (var i = 0; i < dataset._meta[0].data.length; i++) {
          let model = dataset._meta[0].data[i]._model;
          model.x += iDs * offset;
          model.controlPointNextX += iDs * offset;
          model.controlPointPreviousX += iDs * offset;
        }
      }
    }
  }],
  data: {
    labels: ["A"],
    datasets: [{
        label: 'X',
        backgroundColor: 'orange',
        borderWidth: 1,
        data: [5],
        xAxisID: "bar-x-axis1",
        barThickness: 30,
      },
      {
        label: 'Y',
        backgroundColor: 'red',
        data: [10],
        xAxisID: "bar-x-axis2",
        barThickness: 30,
      },
      {
        label: 'Z',
        backgroundColor: 'lightblue',
        data: [15],
        xAxisID: "bar-x-axis3",
        barThickness: 30,
      }
    ]
  },
  options: {
    legend: {
      display: false
    },
    scales: {
      xAxes: [{
          id: "bar-x-axis3",
          display: false
        },
        {
          id: "bar-x-axis2",
          offset: true,
          display: false
        },
        {
          id: "bar-x-axis1",
          offset: true,
          ticks: {
            display: false
          }
        }
      ],
      yAxes: [{
        id: "bar-y-axis1",
        ticks: {
          beginAtZero: true,
          stepSize: 5
        }
      }]
    }
  }
});
canvas {
  max-width: 120px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="150"></canvas>

UPDATE

Please also check this answer that provides a slightly improved solution.

Upvotes: 1

Related Questions