kurkle / chartjs-plugin-autocolors

Automatic color generation for Chart.js
MIT License
64 stars 9 forks source link

Save the generator for the next updates of the same chart #16

Closed thomasjammet closed 1 year ago

thomasjammet commented 1 year ago

Hi!

I have met an issue with a dynamic chart use case. When a new dataset is added after the first initialization of the chart the plugin always creates a new generator which will restart the set of colors.

The following html code is a sample to reproduce the issue, you can see that the new lines added dynamically to the graph always get the initial red color :

<!DOCTYPE html>
<html>
<head>
    <script type='text/javascript' src='//cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js'></script>
    <script type='text/javascript' src='//cdn.jsdelivr.net/npm/moment@2.29.1/moment.min.js'></script>
    <script type='text/javascript' src='//cdn.jsdelivr.net/npm/chartjs-adapter-moment@1.0.0/dist/chartjs-adapter-moment.min.js'></script>
    <script type='text/javascript' src='//cdn.jsdelivr.net/npm/chartjs-plugin-autocolors'></script>
</head>
<body>
    <div style='width:100%; height:100%'>
        <canvas id='MyChart'>Your browser does not support the HTML5 canvas tag.</canvas>
    </div>

    <script>
        const ctx = document.getElementById('MyChart').getContext('2d');

        function rand() {
            return Math.random() * 100;
        }

        let now = Date.now();
        const datasets = [
            {label: 'Curve 1', data: [{x: now, y: rand()}]},
            {label: 'Curve 2', data: [{x: now, y: rand()}]}
        ];
        const chart = new Chart(ctx, {
            type: 'line',
            data: {
                datasets
            },
            options: {
                animation: false,
                scales: {
                    x: {
                        type: 'time',
                        position: 'bottom'
                    }
                }
            },
            plugins: [window['chartjs-plugin-autocolors']]
        });

        // Every second
        let i = 0;
        setInterval(() => {
            if (++i > 60) {
                return; // after 1min no more points
            }

            now = Date.now();
            // Every 5s add a new curve
            if (!(i % 5)) {
                datasets.push({data: [{x: now, y: rand()}], label: 'Curve ' + (datasets.length + 1)});
            }
            // Add a new point for every curve
            for (let dataset of datasets) {
                dataset.data.push({x: now, y: dataset.data[0].y});
            }
            chart.update();
        }, 1000);
    </script>
</body>
</html>

It will look like this : immagine

To avoid this behavior I propose to simply save the generator on the chart instance, let met know your thoughts.

Regards

kurkle commented 1 year ago

Seems like a valid use case.

But I think the offset option would not work as expected with these changes (it can actually be used as a workaround for the issue)

I should really add some tests :)

sonarcloud[bot] commented 1 year ago

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

thomasjammet commented 1 year ago

Hi @kurkle

Thanks for the fast answer and the workaround! I didn't thought to use the offset as a dynamic tool.

I have updated the PR with a correction for the offset which will be used only for initialization, now I let you see if you think it's good to take it.

Let me know if you need something

kurkle commented 1 year ago

Thanks @thomasjammet !