Search code examples
javascriptgraphchart.jsbar-chartlegend-properties

ChartJS Bar chart - Modify legend


I am new to ChartJS and I am trying to build a bar graph. This graph should have the following information:

labels = ['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10']

data = [1,2,3,4,5,6,7,8,9,10]

backgroundColor = ['red','red','red','blue','blue','blue','green','green','black','black']

Until this point, I have managed to build the graph as I expected. But I would like to show a legend with something like:

enter image description here

And not a unique record that I am getting:

enter image description here

How could I make it?

This is what I have managed to do:

<div class="ontainer">
    <canvas id="myChart"></canvas>
</div>

<script>
    const ctx = document.getElementById('myChart');
    const label_legend = ['A','B','C','D']

    const data = {
      labels: ['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10'],
      datasets: [{
        label: 'My First Dataset',
        data: [1,2,3,4,5,6,7,8,9,10],
        backgroundColor: ['red','red','red','blue','blue','blue','green','green','black','black'],
      }]
    };
        
    const config = {
      type: 'bar',
      data: data,
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      },
    };
    new Chart(document.getElementById('myChart'), config);
</script>

Solution

  • You shouldn't make the data which is from different categories into a single category.

    The dataset should be in this format:

    [
      {
        label: 'Red',
        data: [1, 2, 3, null, null, null, null, null, null, null],
        backgroundColor: 'red',
      },
      {
        label: 'Blue',
        data: [null, null, null, 4, 5, 6, null, null, null, null],
        backgroundColor: 'blue',
      },
      {
        label: 'Green',
        data: [null, null, null, null, null, null, 7, 8, null, null],
        backgroundColor: 'green',
      },
      {
        label: 'Black',
        data: [null, null, null, null, null, null, null, null, 9, 10],
        backgroundColor: 'black',
      },
    ]
    

    Transform your input data into the format with:

    const inputs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    const inputColors = [
      'red',
      'red',
      'red',
      'blue',
      'blue',
      'blue',
      'green',
      'green',
      'black',
      'black',
    ];
    
    const colors = new Set(inputColors);
    let groupedDataset = [];
    for (let color of colors) {
      groupedDataset.push({
        label: color.charAt(0).toUpperCase() + color.slice(1),
        data: inputs.map((x, i) => (inputColors[i] === color ? x : null)),
        backgroundColor: color,
      });
    }
    
    const data = {
      labels: ['D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10'],
      datasets: groupedDataset,
    };
    
    const config = {
      type: 'bar',
      data: data,
      options: {
        scales: {
          y: {
            beginAtZero: true,
          },
        },
        skipNull: true,
      },
    };
    

    When the data does not belong to the category, provide the value with null.

    To prevent displaying the bar that is not relevant in the column (for example the bar with blue, green, and black shouldn't appear in D1, D2, and D3), configure skipNull: true in the options.

    Demo @ StackBlitz