0

I'm not a JavaScript dev, and would like some pointers as to how I can convert an array of objects (acquired from a WebAPI call), into arrays suitable for Chart.JS.

My code so far (which works) looks like this:

<canvas id="line-chart" width="800" height="450"></canvas>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>

<script>
    // webapi call returns an object which looks like this
    var raw = {
        message: "Success: 3 entries",
        didError: false,
        errorMessage: null,
        model:
        [
            { time: "2019-09-26T13:19:00", value1: 1, value2: 2, value3: 3, value4: 4 },
            { time: "2019-09-26T13:20:00", value1: 22, value2: 21, value3: 20, value4: 19 },
            { time: "2019-09-26T13:21:00", value1: 10, value2: 20, value3: 40, value4: 70 }
        ]
    };

    // chart.js needs the data to look like this
    var data = {
        labels: ["19:00", "20:00", "20:01"],
        datasets: [
            {
                data: [1, 22, 10],
                label: "Value 1",
                borderColor: "red",
                fill: false
            },
            {
                data: [2, 21, 20],
                label: "Value 2",
                borderColor: "blue",
                fill: false
            },
            {
                data: [3, 20, 40],
                label: "Value 3",
                borderColor: "green",
                fill: false
            },
            {
                data: [4, 19, 70],
                label: "Value 4",
                borderColor: "orange",
                fill: false
            }
        ]
    };

    var options = { title: { display: true, text: 'stuff' } };

    var chart = new Chart(document.getElementById("line-chart"), { type: 'line', data: data, options: options });

</script>

How do I turn my "raw" data into the format that Chart.JS is expecting ? I can make the webAPI (which I wrote) return anything, but didn't think returning chart.js format arrays was the way to go. It currently returns 1440 objects - not 3 !

I don't know js, so I don't know how to do loops and type conversions, so any pointers gratefully received. If possible, I would rather not include extra packages.

5
  • 2
    look into map, for example, raw.model.map( x => x.value1 ) would give you [1, 22, 10] Commented Sep 27, 2019 at 18:55
  • Thanks Dallas. I tried this on my test data, but it doesn't seem to like the "=>" in the script. Do I need a specific version of something, or to include some other scripts ? Commented Sep 30, 2019 at 19:16
  • 1
    .map( x => x.value1) is shorthand for .map( function(x) { return x.value1; }... support is pretty broad now: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Sep 30, 2019 at 19:31
  • Thanks again, tested on my azure VM and it worked just fine. I guess earlier problems are Win7 and IE related. I shall investigate. Commented Sep 30, 2019 at 21:09
  • Many thanks for your (non-shorthand) version - it worked just fine. I now have the chart displayed. It looks a bit naff, but with 1440 data points per series, I thought it might. Time to start digging into Chart.js to find out how to work around the visual issues. Commented Oct 1, 2019 at 19:22

2 Answers 2

1

First, you need to pull apart the model data:

const hashed = raw.model.reduce((acc, item) => {
  Object.keys(acc).forEach(k => acc[k].push(item[k]);
  return acc;
}, {
  value1: [],
  value2: [],
  value3: [],
  value4: [],
});

Then we can turn it into data for chart.js:

const chartData = Object.entries(hashed).map(([label, data]) => ({
  data,
  label,
  fill: false,
}));

Only thing left is to pick colors (random? if not make a mapping from label to color) and maybe format the label/key.

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

Comments

0

The two tasks for conversion is extracting the time stamps to make the label array, and then transposing the values. To iterate over them you can use a simple for loop like

for(obj in model)
{
    model[obj] // Trick here is that obj is an index not the object itself
}

You could also take Dallas comment into consideration and try using map. This would be much more concise. Because once you have the labels set up you could Dallas's example like so to easily transpose the data.

var colors = {/*maps value name to desired color*/};
var valueLabels = {/*maps value name to value labels*/};
var valueNames = [/* list of value names*/];
for(var i in valueNames) {
    var dataVals = raw.model.map(x => x[valueNames[i]]);
    data.datasets.push({
         data: dataVals,
         label: valueLabels[valueNames[i]],
         borderColor: colors[valueNames[i]],
         fill: false
   });
}

Hope this example helps!

Comments

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.