Search code examples
javascripthtmlchartschart.js

ChartJS type changing doesn't work correctly from pie type


I want to build a chart that can adapt when the data changes. I also want to be able to change its type: line, bar, or pie.

I have already made some progress, but I am encountering several errors. First, I encounter an error when I want to update my graph with a slightly different data structure (data3 on JSFiddle).

Error:

"133:44 Uncaught TypeError: Cannot read properties of undefined (reading 'values')"

Also, my biggest problem is that after changing my chart to "pie" mode, if I change to "line" or "bar", then the chart becomes completely wrong and the shape changes no longer make sense. I just want return on line/bar mode in the way to be as same as the graph was on these mode. I need help on this level.

For pie mode, I use the sum of values for each time period:

if (newType === "pie") {
temp.data.labels = temp.data.datasets.map(function(dataset) {
  return dataset.label;
});

temp.data.datasets = [{
  backgroundColor: temp.data.datasets.map(function(dataset) {
    return dataset.backgroundColor;
  }),
  data: temp.data.datasets.map(function(dataset) {
    return dataset.data.reduce((a, b) => a + b, 0);
  })
}];
}

You can see and try it here:

My JSFiddle : Flexible data chart


Solution

  • var data0 = {
        axis: ["June", "July", "August", "September", "October", "November", "December"],
        values: [
            { id: 1, values: [1, 1, 2, 3, 4, 5, 6] },
            { id: 2, values: [1, 2, 4, 8, 3, 2, 4] },
            { id: 3, values: [1, 2, 4, 9, 3, 2, 9] }
        ]
    }
    
    var data1 = {
        axis: ["June", "July", "August"],
        values: [
            { id: 1, values: [2, 1, 3] },
            { id: 2, values: [4, 5, 6] },
            { id: 3, values: [8, 9, 7] }
        ]
    };
    
    var data2 = {
        axis: ["Monday", "Tuesday", "Wednesday", "Thursday"],
        values: [
            { id: 1, values: [10, 12, 11, 10] },
            { id: 2, values: [13, 9, 10, 10] },
            { id: 3, values: [8, 9, 7, 10] }
        ]
    };
    
    var data3 = {
        axis: ["Monday", "Tuesday", "Wednesday", "Thursday2"],
        values: [{ id: 0, values: [10, 12, 11, 10] }]
    };
    
    var config = {
        data: {
            datasets: [
                {
                    label: "company1",
                    fill: false,
                    borderColor: "purple",
                    backgroundColor: "purple"
                },
                {
                    label: "company2",
                    fill: false,
                    borderColor: "green",
                    backgroundColor: "green"
                },
                {
                    label: "company3",
                    fill: false,
                    borderColor: "red",
                    backgroundColor: "red"
                }
            ]
        },
        options: {
            responsive: true
        }
    };
    
    var myChart;
    var currentDataIndex = 0;
    var dataArr = [data0, data1, data2, data3];
    var type = '';
    
    $("#line").click(function() {
        type = 'line';
        mixDataConfig();
    });
    
    $("#bar").click(function() {
        type = 'bar';
        mixDataConfig();
    });
    
    $("#pie").click(function() {
        type = 'pie';
        mixDataConfig();
    });
    
    $("#switch").click(function() {
        currentDataIndex = (currentDataIndex + 1) % dataArr.length; // Increment index and wrap a
        mixDataConfig();
    });
    
    function mixDataConfig() {
        var currentData = dataArr[currentDataIndex];
        var ctx = document.getElementById("canvas").getContext("2d");
    
        // Remove the old chart and all its event handlers
        if (myChart) {
            myChart.destroy();
        }
    
        // Create a deep copy of the config object
        var temp = JSON.parse(JSON.stringify(config));
        temp.type = type;
        var nDatasets = currentData.values.length,
            configDatasets = temp.data.datasets.slice(0, nDatasets);
            // datasets from config object
    
        if(type === "line"){
            temp.data = {
                labels: currentData.axis,
                datasets: configDatasets.map(
                    function(dataset, index){
                        return {
                            ...dataset,
                            //fill: true, // just testing
                            data: currentData.values[index].values
                        };
                    }
                )
            }
        }
        else if(type === "bar"){
            temp.data = {
                labels: currentData.axis,
                datasets: configDatasets.map(
                    function(dataset, index){
                        return {
                            ...dataset,
                            data: currentData.values[index].values
                        };
                    }
                )
            }
        }
        else/* if(type === "pie")*/{
            temp.data.labels = configDatasets.map(({label}) => label);
            temp.data.datasets = [{
                backgroundColor: configDatasets.map(function(dataset) {
                    return dataset.backgroundColor;
                }),
                data: currentData.values.map(function(value) {
                    return value.values.reduce((a, b) => a + b, 0);
                })
            }];
        }
    
        myChart = new Chart(ctx, temp);
    }