Dynamically using array to populate data output for bar chart in javascript

Viewed 826

I am trying to create a bar stack graph using chart.js javascript library. I currently have an array in javascript that contains the following :

0: {labels: "01/01/2020 00:00:00", data: 7433, category: "A"}
1: {labels: "01/01/2020 00:00:00", data: 774, category: "B"}
2: {labels: "01/01/2020 00:00:00", data: 5993, category: "C"}
3: {labels: "30/01/2020 00:00:00", data: 7624, category: "A"}
4: {labels: "30/01/2020 00:00:00", data: 900, category: "B"}
5: {labels: "30/01/2020 00:00:00", data: 5865, category: "C"}
6: {labels: "18/02/2020 00:00:00", data: 7161, category: "A"}
7: {labels: "18/02/2020 00:00:00", data: 1005, category: "B"}
8: {labels: "18/02/2020 00:00:00", data: 5940, category: "C"}

Below is the AJAX request to put the data into an array and now i need to dynamically set the data to output a stack chart

 // STACK BAR CHART
var stackBarData = [];
var stackBarLabels = [];

$.ajax({
    type: "POST",
    async: false,
    url: "ExecView.aspx/ReturnStackBarData",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (data) {
        var stackbarDatas = data.d;
        stackBarData = new Array(stackbarDatas.length);

        console.log(stackBarData);

        for (i = 0; i < stackbarDatas.length; i++) {

            stackBarData[i] = { labels: stackbarDatas[i].label, data: stackbarDatas[i].data, category: stackbarDatas[i].category };
        }

        console.log(stackBarData); // ARRAY OUTPUT ABOVE




    }
});


var BarpopData = {
    datasets: [{
        data: stackBarData
    }],



};

I expect all the data in the array with 01/01/20 to be my first label on the X axis and Category A to be the lowest stack with data 7433. Then I expect category B to be middle stack with data 774. Then i expect category C to be the highest stack with data 5933. The i expect another bar stack with date 30/01/2020 data.

I need this to be dynamic looking at the array as data always changes.

How can I dynamically do this - ensuring min and max Y axis is auto so is shows a good bar stack graph?

I have a JS Fiddle: https://jsfiddle.net/1eq8w0Lx/ of what i expect the outcome to look like. I need the hard coded values to be dynamic from my array. How do i achieve this output?

4 Answers

With reference to your jsfiddle link, I have modified your ajax success method logic. may this might help you to achieve the desired result

success: function (data) {
    var stackbarDatas = data.d;
    stackBarData = new Array(stackbarDatas.length);

    var dataSet = stackbarDatas.map(x=>({label: x.category, data: [x.data]}))
    var labels = stackbarDatas.map(x=>(x.label))

    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
                                   type: 'bar',
                                   data: {
                                           labels: labels ,
                                           datasets: dataSet,
                                           options: {
                                                  ...
                                                  //rest settings as it is
}

You can find a working example here https://jsfiddle.net/k9j6h3tc/2/

Gist:

  1. Setup your chart. The data can be empty.
    const myChart = new Chart(document.getElementById("myChart"), {
      type: 'bar',
      data: {
        labels  : [],
        datasets: [
          {
            label          : 'A',
            data           : [],
            backgroundColor: [ ... ],
            borderColor    : [ ... ],
            borderWidth    : 2
          },
          {
            label          : 'B',
            data           : [],
            backgroundColor: [ ... ],
            borderColor    : [ ... ],
            borderWidth    : 2
          },
          {
            label          : 'C',
            data           : [],
            backgroundColor: [ ... ],
            borderColor    : [ ... ],
            borderWidth    : 2
          },
        ],
      },
      options: { ... }
    })
    
  2. $.ajax callback can look like this:
    function on_success(data) {
    myChart.data.labels = [...new Set(data.map(el => el.labels.slice(0,-9)))];
      ["A", "B", "C"].forEach((cat, idx) => {
        myChart.data.datasets[idx].data,
        data.filter(el => el.category === cat).map(el => el.data)
      });
      myChart.update();
    }
    
  3. Don't recreate the chart. Use myChart.update().

First of all, sort the data to make sure they are in the correct order:

const priority = ['A', 'B', 'C']
data.sort((a, b) => {
  const aDate = new Date(a.labels).getTime()
  const bDate = new Date(b.labels).getTime()
  if (aDate === bDate) {
    return priority.indexOf(a.category) - priority.indexOf(b.category)
  }
  return aDate - bDate
})

The labels is easy to get:

const labels = [...new Set(data.map(el => el.labels.slice(0, -9)))]

As for the datasets, its order should be the same as the array priority:

const datasets = priority.map(p => ({ label: p, data: [] }))
for (const d of data) {
  const index = priority.indexOf(d.category)
  datasets[index].data.push(d.data)
}
var stackbarDatas = data.d;
        stackBarData = new Array(stackbarDatas.length);

        stackBarData = stackbarDatas.map(x => ({ category: x.category, data: [x.data], backgroundColor: x.backgroundColor, borderColor: x.borderColor, borderWidth: x.borderWidth }))
        stackBarLabels = stackbarDatas.map(x => (x.label))

        uniqueLabels = stackBarLabels.filter((v, i, a) => a.indexOf(v) === i); 


        console.log(JSON.stringify(stackBarData));


        stackBarData.forEach(d => {
            var categoryName = d.category;
            if (!groups[d.category]) {
                groups[d.category] = {
                    label: d.category,
                    data: [],
                    backgroundColor: [],
                    borderColor: [],
                    borderWidth: d.borderWidth
                };
            }
            groups[d.category].data.push(d.data[0]);
            groups[d.category].backgroundColor.push(d.backgroundColor);
            groups[d.category].borderColor.push(d.borderColor);
        });

        stackBarData = Object.values(groups);
Related