0

I created the following question Horizontal overlapping of bars, not whole graph which was kindly answered (I was advised to create a new question!). Whilst the answer worked great - I have 2x charts on the same page which for some reason throws a Cannot read property 'data' of undefined error.

I don't want to include the entirity of my 2 charts but the afterUpdate code that moves the bars is as follows:

function(chart) {
    var datasets = chart.config.data.datasets;

    console.log(datasets);

    for (let iDs = 1; iDs < datasets.length; iDs++) {
        let dataset = datasets[iDs];

        // I added the following line however stacks the graph and doesn't display it correctly like the first
        if (typeof dataset._meta[0] !== 'undefined'){
            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;
            }
        }
    }
}

I have added the typeof check to the code which at least renders the graph, however I would like both graphs to function the same way whereas the addition of the typeof check then just stacks the graph and ignores the code to move the bars.

This can best be seen in action in the following fiddle: https://jsfiddle.net/ycpj7g8w/

Antony
  • 3,875
  • 30
  • 32

1 Answers1

1

The described behavior is weird, given that both charts work fine if they're created isolated from each other. The problem can be solved by changing the afterUpdate function and make use of the chart's .getDatasetMeta(index) function to obtain the dataset's metadata.

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

Please take a look at your amended and runnable code below:

Chart.defaults.global.legend.labels.usePointStyle = true;
Chart.defaults.scale.gridLines.drawOnChartArea = false;

var offset = 6;

new Chart('graph_1', {
  "type": "bar",
  "data": {
    "labels": ["2020-08-01", "2020-09-01", "2020-10-01"],
    "datasets": [{
        "label": "Title test 1",
        "data": [30, 20, 60],
        "xAxisID": "bar-x-axis-1",
        "barThickness": 14,
        "backgroundColor": "rgba(241,213,157,1)",
        "borderColor": "rgba(241,213,157,1)",
        "pointBackgroundColor": "rgba(241,213,157,1)"
      },
      {
        "label": "Title test 2",
        "data": [30, 20, 60],
        "xAxisID": "bar-x-axis-2",
        "barThickness": 14,
        "backgroundColor": "rgba(237,141,120,1)",
        "borderColor": "rgba(237,141,120,1)",
        "pointBackgroundColor": "rgba(237,141,120,1)"
      },
      {
        "label": "Title test 3",
        "data": [30, 20, 60],
        "xAxisID": "bar-x-axis-3",
        "barThickness": 14,
        "backgroundColor": "rgba(120,199,212,1)",
        "borderColor": "rgba(120,199,212,1)",
        "pointBackgroundColor": "rgba(120,199,212,1)"
      }
    ]
  },
  "plugins": [{
    "afterUpdate": function(chart) {
      let datasets = chart.config.data.datasets;
      for (let iDs = 1; iDs < datasets.length; iDs++) {
        let meta = chart.getDatasetMeta(iDs);
        for (var i = 0; i < meta.data.length; i++) {
          let model = meta.data[i]._model;
          model.x += iDs * offset;
          model.controlPointNextX += iDs * offset;
          model.controlPointPreviousX += iDs * offset;
        }
      }
    }
  }],
  "curvature": 0.2,
  "options": {
    "legend": {
      "display": true,
      "position": "bottom"
    },
    "scales": {
      "yAxes": [{
        "ticks": {
          "beginAtZero": true,
          "stepSize": 25
        }
      }],
      "xAxes": [{
          "id": "bar-x-axis-3",
          "display": false
        },
        {
          "id": "bar-x-axis-2",
          "display": false,
          "offset": true
        },
        {
          "id": "bar-x-axis-1",
          "display": false,
          "offset": true
        }
      ]
    },
    "barRoundness": 0.5
  }
});

new Chart('graph_2', {
  "type": "bar",
  "data": {
    "labels": ["2020-06-01", "2020-07-01", "2020-08-01", "2020-09-01", "2020-10-01"],
    "datasets": [{
        "label": "Stage 1",
        "data": [30, 75, 60, 90],
        "xAxisID": "bar-x-axis-1",
        "barThickness": 14,
        "backgroundColor": "rgba(241,213,157,1)",
        "borderColor": "rgba(241,213,157,1)",
        "pointBackgroundColor": "rgba(241,213,157,1)"
      },
      {
        "label": "Stage 2",
        "data": [40, 66, 60, 90],
        "xAxisID": "bar-x-axis-2",
        "barThickness": 14,
        "backgroundColor": "rgba(237,141,120,1)",
        "borderColor": "rgba(237,141,120,1)",
        "pointBackgroundColor": "rgba(237,141,120,1)"
      },
      {
        "label": "Stage 3",
        "data": [50, 45, 60, 90],
        "xAxisID": "bar-x-axis-3",
        "barThickness": 14,
        "backgroundColor": "rgba(120,199,212,1)",
        "borderColor": "rgba(120,199,212,1)",
        "pointBackgroundColor": "rgba(120,199,212,1)"
      },
      {
        "label": "Stage 4",
        "data": [60, 35, 60, 90],
        "xAxisID": "bar-x-axis-4",
        "barThickness": 14,
        "backgroundColor": "rgba(5,114,159,1)",
        "borderColor": "rgba(5,114,159,1)",
        "pointBackgroundColor": "rgba(5,114,159,1)"
      },
      {
        "label": "Stage 5",
        "data": [70, 25, 60, 90],
        "xAxisID": "bar-x-axis-5",
        "barThickness": 14,
        "backgroundColor": "rgba(2,41,112,1)",
        "borderColor": "rgba(2,41,112,1)",
        "pointBackgroundColor": "rgba(2,41,112,1)"
      }
    ]
  },
  "plugins": [{
    "afterUpdate": function(chart) {
      let datasets = chart.config.data.datasets;
      for (let iDs = 1; iDs < datasets.length; iDs++) {
        let meta = chart.getDatasetMeta(iDs);
        for (var i = 0; i < meta.data.length; i++) {
          let model = meta.data[i]._model;
          model.x += iDs * offset;
          model.controlPointNextX += iDs * offset;
          model.controlPointPreviousX += iDs * offset;
        }
      }
    }
  }],
  "curvature": 0.2,
  "options": {
    "legend": {
      "display": true,
      "position": "bottom"
    },
    "scales": {
      "yAxes": [{
        "ticks": {
          "beginAtZero": true,
          "stepSize": 25
        }
      }],
      "xAxes": [{
          "id": "bar-x-axis-5",
          "display": false,
        },
        {
          "id": "bar-x-axis-4",
          "display": false,
          "offset": true
        },
        {
          "id": "bar-x-axis-3",
          "display": false,
          "offset": true
        },
        {
          "id": "bar-x-axis-2",
          "display": false,
          "offset": true
        },
        {
          "id": "bar-x-axis-1",
          "display": false,
          "offset": true
        }
      ]
    },
    "barRoundness": 0.5
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="graph_1"></canvas>
<canvas id="graph_2"></canvas>

Please note that when all charts contained on a page use the same plugin function, you don't have to repeat the code but can simply register it once through Chart.pluginService.register as shown in this answer.

uminder
  • 23,831
  • 5
  • 37
  • 72