1

I am trying to create a dynamic dataset for my Chart.js project but I am having trouble, here is an example of the dataset pulled from getpromorevenuechart.php:

[{"mmyy":"2019-12","promocode":"promo1","amount":"2776"},{"mmyy":"2020-01","promocode":"promo1","amount":"1245"},{"mmyy":"2020-01","promocode":"promo2","amount":"179"}]

Here is the code I am currently using:

    function getPromoRChartData() {
    var city = document.getElementById("cityselect").value;
$.ajax({
        type: 'GET',
        url: 'getpromorevenuechart.php',
        dataType: 'json',
        data: {  city:city, },
        success: function(response) {
          //console.log (response);

          function collate(d) {
            return d.reduce(function(prev, cur, index) {
                var ret = {};
                for (var prop in cur) {
                    if (index === 0) {
                        ret[prop] = [];
                    } else {
                        ret[prop] = prev[prop];
                    }
                    ret[prop].push(cur[prop]);
                }
                return ret;
            }, {});
        }

          var reduced = collate(response);

var ctx = document.getElementById('promorChart').getContext('2d');

var chartColors = window.chartColors;
var color = Chart.helpers.color;

var fleetmChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: reduced.mmyy,
        datasets: [{
        label: reduced.promocode,
        data: reduced.amount,
    },
    options: {
        scales: {
            xAxes: [{
              stacked: false
            }],
            yAxes: [{
              stacked: false,
                ticks: {
                    // Include a dollar sign in the ticks
                    callback: function(value, index, values) {
                        return '$' + value;
                    }
                }
            }]
        },
        tooltips: {
            callbacks: {
                label: function(tooltipItems, data) {
                    return "$" + tooltipItems.yLabel.toString();
                }
            }
        },
        responsive: true,
        elements: {
        }
    }
});

But that code isn't displaying the way I want. The way I want this to look is like the following:

data: {
        labels: ["2019-12", "2020-01"],
        datasets: [{
            label: 'promo 1',
            data: [2776, 1245]
        },
        {
            label: 'promo 2',
            data: [0, 179]
        }
        ]
    },

What it seems I need to do is create a for each type thing and I would also need to introduce a 0 for mm/yy when that promo isn't used. I am very unsure how to do all this. Can someone give me some direction and assist me in how to make this happen?

Edit:

Trying to incorporate uminder's code below:

    function getPromoRChartData() {
    var city = document.getElementById("cityselect").value;
$.ajax({
        type: 'GET',
        url: 'getpromorevenuechart.php',
        dataType: 'json',
        data: {  city:city, },
        success: function(response) {
const labels = Array.from(new Set(response.map(c => c.mmyy))).sort();
const promocodes = Array.from(new Set(response.map(c => c.promocode))).sort();
const datasets = promocodes.map(pc => ({ label: pc, data: []}));
labels.forEach(l => {    
    for (let pc of promocodes) {
      let city = response.find(c => c.mmyy == l && c.promocode == pc);
        datasets.find(ds => ds.label == pc).data.push(city ? city.amount : 0);
    }
});

var dynlabels = JSON.stringify(labels);
var dyndatasets = JSON.stringify(datasets, undefined, "  ");

console.log (dynlabels);
console.log (dyndatasets);

var ctx = document.getElementById('promorChart').getContext('2d');

var chartColors = window.chartColors;
var color = Chart.helpers.color;

var promorChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: [dynlabels],
        datasets: [{
            dyndatasets
        }
        ]
    },

    options: {
        scales: {
            xAxes: [{
              stacked: false
            }],
            yAxes: [{
              stacked: false,
                ticks: {
                    // Include a dollar sign in the ticks
                    callback: function(value, index, values) {
                        return '$' + value;
                    }
                }
            }]
        },
        tooltips: {
            callbacks: {
                label: function(tooltipItems, data) {
                    return "$" + tooltipItems.yLabel.toString();
                }
            }
        },
        responsive: true,
        elements: {
        }
    }
});

does not render the graph correctly at all, here is a screen shot of the graph rendered (using the above input data):

enter image description here

and here is the console output:

    ["2019-12","2020-01"]
    success — Script Element 2:1382[
      {
        "label": "promo1",
        "data": [
          "2776",
          "1245"
        ]

  },
  {
    "label": "promo2",
    "data": [
      0,
      "179"
    ]
  }
]

If I remove the [{}] around dyndatasets I get the error:

TypeError: Attempted to assign to readonly property.

and if I remove the brackets from dynlabels this happens:

enter image description here

Oddly enough... if I copy directly from the console and past in the fields it works, so I don't know what gives? Is it like a formatting error?

2
  • what do you mean by "create a for each type thing"? where did you get that info from? Commented Jan 26, 2020 at 9:45
  • I don't know maybe I'm wrong Commented Jan 26, 2020 at 10:28

1 Answer 1

1

Here's a code sample that illustrates how to convert the response into the data (labels and datasets) required by chart.js.

const response = [ 
   { 
      "mmyy":"2019-12",
      "promocode":"promo1",
      "amount":"2776"
   },
   { 
      "mmyy":"2020-01",
      "promocode":"promo1",
      "amount":"1245"
   },
   { 
      "mmyy":"2020-01",
      "promocode":"promo2",
      "amount":"179"
   }
];

const labels = Array.from(new Set(response.map(c => c.mmyy))).sort();
const promocodes = Array.from(new Set(response.map(c => c.promocode))).sort();
const datasets = promocodes.map(pc => ({ label: pc, data: []}));
labels.forEach(l => {    
    for (let pc of promocodes) {
    	let city = response.find(c => c.mmyy == l && c.promocode == pc);
        datasets.find(ds => ds.label == pc).data.push(city ? Number(city.amount) : 0);
    }
});

console.log("labels: " + JSON.stringify(labels));
console.log("datasets: " + JSON.stringify(datasets, undefined, "  "));

Please have a look at the following JSFiddle

Sign up to request clarification or add additional context in comments.

10 Comments

There seems to a be a strange formatting error, check above and please advise.
I updated my answer and corrected an error in my sample code. I now convert amount to a number.
Still not working, it's also the label, as you can see on the bottom it is not displaying correctly,
You must not use JSON.stringify in the real code, I did this only to show nice output when logging to the console (see jsfiddle.net/cer9fwum).
Can you help me add colors to that as well, from this dataset of colors?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.