Search code examples
javascriptarraysdynamicapexcharts

How to dynamically create and name N data series for ApexCharts using other arrays?


I'm using ApexCharts to display data from a database, and it works perfectly fine until I have to create multiple data series. I get the data in the form of multiple arrays like so (nb: I don't get a list of fruits, it's for the sake of example)

var fruits = ["apple","apple","apple","apple","apple"]; // Name of the fruit
var dates = ["2019-04-01","2019-04-02","2019-04-03","2019-04-04","2019-04-05"];
var values = [14,9,17,5,11];

Where fruits[0] goes with dates[0] and values[0] (think of them as row in a database).

In this case I have only one data series to pass to ApexCharts and I can do it like this :

var matchedData = [];

// I create nested arrays in matchedData, each array corresponding to a tuple, like so : matched[0] = [dates[0],values[0]]
for(let i = 0; i < fruits.length; i++) {
    date = new Date(dates[i]); // To transform the date string to Javascript timestamp
    matchedData[i] = [date.getTime(),values[i]];
}

var options = {
    chart: {
        type: 'line'
    },
    series: [{
        label: "Data",
        data: matchedData
    }],
    xaxis: {
        type: 'datetime'
    },
}

var chart = new ApexCharts(document.getElementById('chart'), options);
chart.render();

But it only works when the "fruits" array contains solely one kind of fruit and not different kinds. So if my arrays are like this :

var fruits = ["apple","banana","apple","banana","strawberry"];
var dates = ["2019-04-01","2019-04-02","2019-04-03","2019-04-04","2019-04-05"];
var values = [14,9,17,5,11];

I have to dynamically create 3 arrays named each after a fruit (so in this case, "apple", "banana" and "strawberry"), each of them containing the corresponding date and value. Each array would look like this :

apple = [
            ["2019-04-01", 14], // I wrote the time in string for readability here but in reality it would be written in the JavaScript timestamp format
            ["2019-04-03", 17]
        ];

banana = [
            ["2019-04-02", 9], 
            ["2019-04-04", 5]
         ];

strawberry = [
                 ["2019-04-05",11]
             ];

And these data series would be passed to ApexCharts like this :

var options = {
        chart: {
            type: 'line'
        },
        series: [
            {
                label: "apple",
                data: apple
            },{
                label: "banana",
                data: banana
            },{
                label: "strawberry",
                data: strawberry
            }
        ],
        xaxis: {
            type: 'datetime'
        },
    }

var chart = new ApexCharts(document.getElementById('chart'), options);
chart.render();

My problem is the following :

I don't know how many series I will need to create until runtime, I don't know their name, and I don't know either how to pass them to ApexCharts dynamically (if there are N series, I need N {label/data} clauses).

I've got the start of a solution for dynamically creating an array for each fruit, it looks like this :

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

    if(fruits[i] in window) {
        date = new Date(dates[i]);
        window[fruits[i]].push([date.getTime(),values[i]]);
    } else {
        window[lines[i]] = [];
        date = new Date(dates[i]);
        window[lines[i]].push([date.getTime(),values[i]]);
    }

}

And I can then later access each array but only if already know the different values there are in the "fruits" array.


Solution

  • I found myself. I used the window global object like I said earlier like so :

    for(let i = 0; i < fruits.length; i++) {
    
        if(!(fruits[i] in window)) {
            window[fruits[i]] = [];
        }
    
        date = new Date(dates[i]);
        window[fruits[i]].push([date.getTime(),values[i]]);
    }
    

    Then I made an array listing each unique name from the "fruits" array by using this function :

    var fruitsName = fruits.unique();
    
    Array.prototype.unique = function() {
        return this.filter(function (value, index, self) {
            return self.indexOf(value) === index;
        });
    }
    

    And then I iterated on the unique names array to add each series to my chart from ApexCharts using the appendSeries() method like this :

    for(let i = 0; i < fruitsName.length; i++) {
        chart.appendSeries({
            name: fruitsName[i],
            data: window[fruitsName[i]]
        });
    }