Marcus Ohlsson
Marcus Ohlsson

Reputation: 267

Add dynamic dataset to chart.js

I'm trying to add lines to a chart.js chart dynamically where I don't know how many datasets I have I've been banged my head on this for two days now...

I have a list containing Year, Month and Value:

    public int Month { get; set; }
    public int Year { get; set; }
    public int Value { get; set; }

My HTML is just a canvas for the chart:

<div>
<canvas id="myChart"> </canvas>
</div>

I populate the chart like this:

 var dataList = [];
    var lableList = [];
    @foreach (var dataInput in Model.TurnoverByReservation)
    {

        @:dataList.push("@dataInput.Value");
        @:lableList.push("@dataInput.MonthName");
    }

    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: lableList,
            datasets: [
                {
                    label: 'Booking value',
                    data: dataList,
                    backgroundColor: backgroundColors,
                    borderColor: borderColors,
                    borderWidth: 1
                }
            ]
        },
        options: {
            scales: {
                yAxes: [
                    {
                        ticks: {
                            beginAtZero: true,
                            callback: function(value, index, values) {
                                if (parseInt(value) >= 1000) {
                                    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                                } else {
                                    return value;
                                }
                            }
                        }
                    }
                ]
            }
        }
    });

So the question is; how can I add different datasets to the chart so that I can use something like this?

@foreach (var year in Model.TurnoverByReservation.OrderBy(x =>x.Month).GroupBy(x => x.Year))
{
foreach (var value in year)
 {
    //Add the value to the dataset, somehow...
 }
}

Upvotes: 3

Views: 6801

Answers (2)

Marcus Ohlsson
Marcus Ohlsson

Reputation: 267

This is the final and working solution, big thanks to @tektiv for all assistance

var borderColors = [
    'rgba(255,99,132,1)',
    'rgba(54, 162, 235, 1)',
    'rgba(255, 206, 86, 1)',
    'rgba(75, 192, 192, 1)',
    'rgba(153, 102, 255, 1)',
    'rgba(255, 159, 64, 1)'
];
var backgroundColors = [
    'rgba(255, 99, 132, 0.2)',
    'rgba(54, 162, 235, 0.2)',
    'rgba(255, 206, 86, 0.2)',
    'rgba(75, 192, 192, 0.2)',
    'rgba(153, 102, 255, 0.2)',
    'rgba(255, 159, 64, 0.2)'
];
        var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
            label: "#value",
            datasets: []
        },
        options: {
            scales: {
                yAxes: [
                    {
                        ticks: {
                            beginAtZero: true
                        }
                    }
                ]
            }
        }
    });

    @{StringBuilder valueObj = new StringBuilder();}

    var objModel = new Object();

    var myArray = [];
    @foreach (var years in Model.TurnoverByReservation.OrderBy(x => x.Month).GroupBy(x => x.Year))
    {
        foreach (var value in years)
        {
            @:myArray.push("@value.Value");
        }
        @:objModel["@years.Key"] = myArray;
        @:myArray = [];
    }

    var colorInt = 0; //Used to set a variable background and border color

    for (year in objModel) {
        // You create a new dataset with empty values and the year as the label
        var newDataset = {
            label: year,
            data: [],
            backgroundColor: backgroundColors[colorInt],
            borderColor:borderColors[colorInt]
        };
        colorInt += 1;
        // For every value for this specific year ..
        for (value in objModel[year]) {
            // You populate the newly created dataset
            newDataset.data.push(objModel[year][value]);
        }

        // Then you add the dataset to the charts' ones
        myChart.config.data.datasets.push(newDataset);
    }

    // Finally, make sure you update your chart, to get the result on your screen
    myChart.update();

Upvotes: 2

tektiv
tektiv

Reputation: 14187

You can populate your datasets array whenever you want, even after calling the new Chart() function by editing the array datasets stored in myChart.config.data.

Let's say you get something like this from your query

var model = {
    2015: [20, 12, 32, 8, 25, 14, 20, 12, 32, 8, 25, 14],
    2016: [17, 26, 21, 41, 8, 23, 17, 26, 21, 41, 8, 23],
    2017: [23, 15, 8, 24, 38, 20, 23, 15, 8, 24, 38, 20]
};

You loop into it, and store every data you have in you new datasets :

// For every year in your data ...
for (year in model) {
    // You create a new dataset with empty values and the year as the label
    var newDataset = {
        label: year,
        data: []
    };

    // For every value for this specific year ..
    for (value in model[year]) {
        // You populate the newly created dataset
        newDataset.data.push(model[year][value]);
    }

    // Then you add the dataset to the charts' ones
    myChart.config.data.datasets.push(newDataset);
}

// Finally, make sure you update your chart, to get the result on your screen
myChart.update();

Make sure you initiate your chart with at least the following :

var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        // You need as much labels as the number of values you have
        labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 
        // This makes sure you'll get something with `myChart.config.data.datasets`
        datasets: []
    }
});

If your model structure is different, you should still be able to change a bit the loop to get it working.

You can check a result with default data in this fiddle.

Upvotes: 6

Related Questions