Search code examples
chart.js

Bar Chart with Overlaid Bars Spanning Across Entire Chart


I am attempting to create a Chart.js that displays the main dataset as a bar chart. There will be YellowBar and RedBar datasets that will be overlaid on top of the main dataset, but these need to span the entire width of the bar chart as shown in the yellow and red bars in the example below. Note that I added the yellow and red bars in a photo editing program - they are not generated by Chart.js currently.

As shown, the options for YellowBar and RedBar are selectable from a drop menu. Their values should update dynamically based on the selection.

I should note that the number of columns for dataset will vary depending on the one selected in the drop menu.

chart example

The code I have is as follows. This generates the main dataset bar chart. My efforts to add chart data for YellowBar and RedBar using help from ChatGPT only confused things, so I have omitted them.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Bar Chart with Dataset Selection</title>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
</head>
<body>
  <div>
    <canvas id="myChart" width="3" height="2"></canvas>
    <label for="datasetSelect">Select Map:</label>
    <select id="datasetSelect">
      <option value="dataset1">Map #1</option>
      <option value="dataset2">Map #2</option>
    </select>
  </div>
  <div>
    <label for="YellowBar">Select Option #1:</label>
    <select id="YellowBar">
      <option value="YB1">Thing #1</option>
      <option value="YB2">Thing #2</option>
    </select>
  </div>
  <div>
    <label for="RedBar">Select Option #2:</label>
    <select id="RedBar">
      <option value="RB1">Thing #3</option>
      <option value="RB2">Thing #4</option>
    </select>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      var ctx = document.getElementById('myChart').getContext('2d');
      var datasets = {
        dataset1: {
          labels: ['Item A',
             'Item B',
             'Item C',
             'Item D'],
          data: [[612,1836],
             [612,1836],
             [1165,3029],
             [1576,3636]]
        },
        dataset2: {
          labels: ['Item X',
             'Item Y',
             'Item Z'],
          data: [[612,1836],
             [700,2100],
             [945,2458]]
        },
      };

      var YellowBar = {
        YB1: {
          data: [[800,1400]]},
        YB2: {
          data: [[1000,1600]]},
      };

        var RedBar = {
        RB1: {
          data: [[2300,2800]]},
        RB2: {
          data: [[2500,3000]]},
      };

      var chart = new Chart(ctx, {
        type: 'bar',
        data: {
          labels: datasets.dataset1.labels,
          datasets: [{
            label: 'Dataset 1',
            data: datasets.dataset1.data,
            backgroundColor: 'rgba(29, 20, 124, 0.8)',
            borderColor: 'rgba(29, 20, 124, 0.8)',
            borderWidth: 1
          }]
        },
        options: {
          plugins: {
            legend: {
              display: false
            }
          },
          scales: {
            x: {
              title: {
                display: true,
                text: 'X-axis Label'
              },
              ticks: {
                autoSkip: false,
                maxRotation: 90,
                minRotation: 90
              }
            },
            y: {
              title: {
                display: true,
                text: 'Y-axis Label'
              },
              ticks: {
                beginAtZero: true
              }
            }
          }
        }
      });

      document.getElementById('datasetSelect').addEventListener('change', function() {
        var selectedDataset = this.value;
        chart.data.labels = datasets[selectedDataset].labels;
        chart.data.datasets[0].label = selectedDataset;
        chart.data.datasets[0].data = datasets[selectedDataset].data;
        chart.update();
      });
    });
  </script>
</body>
</html>

Solution

  • I would suggest having a look at the plugin chartjs-plugin-annotation, specifically the box type. Really simple plugin to register on your chart, and then specify where you want it to sit:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Bar Chart with Dataset Selection</title>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
      <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation/dist/chartjs-plugin-annotation.min.js"></script>
    </head>
    <body>
      <div>
        <canvas id="myChart" width="3" height="2"></canvas>
        <label for="datasetSelect">Select Map:</label>
        <select id="datasetSelect">
          <option value="dataset1">Map #1</option>
          <option value="dataset2">Map #2</option>
        </select>
      </div>
      <div>
        <label for="YellowBar">Select Option #1:</label>
        <select id="YellowBar">
          <option value="YB1">Thing #1</option>
          <option value="YB2">Thing #2</option>
        </select>
      </div>
      <div>
        <label for="RedBar">Select Option #2:</label>
        <select id="RedBar">
          <option value="RB1">Thing #3</option>
          <option value="RB2">Thing #4</option>
        </select>
      </div>
    
      <script>
        document.addEventListener('DOMContentLoaded', function() {
          var ctx = document.getElementById('myChart').getContext('2d');
          var datasets = {
            dataset1: {
              labels: ['Item A',
                 'Item B',
                 'Item C',
                 'Item D'],
              data: [[612,1836],
                 [612,1836],
                 [1165,3029],
                 [1576,3636]]
            },
            dataset2: {
              labels: ['Item X',
                 'Item Y',
                 'Item Z'],
              data: [[612,1836],
                 [700,2100],
                 [945,2458]]
            },
          };
    
          var YellowBar = {
            YB1: {
              data: [[800,1400]]},
            YB2: {
              data: [[1000,1600]]},
          };
    
            var RedBar = {
            RB1: {
              data: [[2300,2800]]},
            RB2: {
              data: [[2500,3000]]},
          };
    
          var chart = new Chart(ctx, {
            type: 'bar',
            data: {
              labels: datasets.dataset1.labels,
              datasets: [{
                label: 'Dataset 1',
                data: datasets.dataset1.data,
                backgroundColor: 'rgba(29, 20, 124, 0.8)',
                borderColor: 'rgba(29, 20, 124, 0.8)',
                borderWidth: 1
              }]
            },
            options: {
              plugins: {
                legend: {
                  display: false
                },
                annotation: {
                 annotations: {
                    box1: {
                    type: 'box',
                    xMin: -0.5,
                    xMax: datasets.dataset1.labels.length,
                    yMin: YellowBar.YB1.data[0][0],
                    yMax: YellowBar.YB1.data[0][1],
                    backgroundColor: 'rgba(255, 99, 132, 0.9)'
                  },
                  box2: {
                  type: 'box',
                  xMin: -0.5,
                  xMax: datasets.dataset1.labels.length,
                  yMin: RedBar.RB1.data[0][0],
                  yMax: RedBar.RB1.data[0][1],
                  backgroundColor: 'rgba(227, 201, 2, 0.9)'
                 }
                   }
                 },
                 },
              scales: {
                x: {
                  title: {
                    display: true,
                    text: 'X-axis Label'
                  },
                  ticks: {
                    autoSkip: false,
                    maxRotation: 90,
                    minRotation: 90
                  }
                },
                y: {
                  title: {
                    display: true,
                    text: 'Y-axis Label'
                  },
                  ticks: {
                    beginAtZero: true
                  }
                }
              }
            }
          });
    
          document.getElementById('datasetSelect').addEventListener('change', function() {
            var selectedDataset = this.value;
            chart.data.labels = datasets[selectedDataset].labels;
            chart.data.datasets[0].label = selectedDataset;
            chart.data.datasets[0].data = datasets[selectedDataset].data;
            chart.update();
          });
    
    // These two event listeners 
    document.getElementById('YellowBar').addEventListener('change', 
    function() {
    var selectedYellowBar = this.value;
      chart.options.plugins.annotation.annotations.box1.yMin = 
    YellowBar[selectedYellowBar].data[0][0];
      chart.options.plugins.annotation.annotations.box1.yMax = 
    YellowBar[selectedYellowBar].data[0][1];
      chart.update();
    });
    
    document.getElementById('RedBar').addEventListener('change', 
    function() {
    var selectedRedBar = this.value;
      chart.options.plugins.annotation.annotations.box2.yMin = 
    RedBar[selectedRedBar].data[0][0];
      chart.options.plugins.annotation.annotations.box2.yMax = 
    RedBar[selectedRedBar].data[0][1];
      chart.update();
    });
        });
      </script>
    </body>
    </html>