DB2: Migrating chart.js from DB1

@Buckskin - I got it working!! And ChatGPT (after 2 days) was finally able to simplify the code a bit.

Below is the flow in case it helps someone:

[{"id":"f8c7169724fa4baf","type":"inject","z":"3d460c91742c0584","name":"Updated Meter Data (w/payload1)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"labels\":[\"2025-07-15\",\"2025-07-16\",\"2025-07-17\",\"2025-07-18\",\"2025-07-19\",\"2025-07-20\",\"2025-07-21\",\"2025-07-22\",\"2025-07-23\",\"2025-07-24\",\"2025-07-25\",\"2025-07-26\",\"2025-07-27\",\"2025-07-28\",\"2025-07-29\",\"2025-07-30\",\"2025-07-31\",\"2025-08-01\"],\"teslaFromGrid\":[30.548,44.488,28.566,54.282,13.648,0.928,4.604,6.062,6.962,6.876,5.488,7.96,39.938,36.71,46.704,50.692,53.876,45.47],\"meterFromGrid\":[30.869,44.852,28.843,54.751,13.73,0.943,4.668,6.118,7.03,6.928,5.534,8.028,40.279,37.037,47.157,51.154,54.372,45.84],\"teslaToGrid\":[-0.11,-0.07,-0.045,-0.024,-16.551,-9.227,-4.552,-10.018,-4.244,-9.096,-2.726,-0.091,-0.063,-0.076,-0.074,-0.066,-0.057,-0.065],\"meterToGrid\":[-0.201,-0.154,-0.1,-0.068,-16.757,-9.393,-4.664,-10.154,-4.358,-9.246,-2.804,-0.162,-0.113,-0.122,-0.126,-0.083,-0.074,-0.07]}","payloadType":"json","x":384.8345642089844,"y":320.82720947265625,"wires":[["8e254e2bad333e5c"]]},{"id":"8e254e2bad333e5c","type":"ui-template","z":"3d460c91742c0584","group":"5cd7a2a79d14beb5","page":"","ui":"","name":"Clean Temlate for Testing","order":1,"width":"22","height":"10","head":"","format":"<template>\n  <div class=\"base-container\">\n    <div class=\"chart-container\"><canvas ref=\"meterchart0\" /></div>\n  </div>\n</template>\n\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n\n<script>\n  export default {        \n        data() {\n            return {\n                isChartLoaded: false,\n                dataSets: [],\n            }\n        },\n\n        watch: {\n            msg: function () {\n                if (this.isChartLoaded && this.msg.payload && this.msg.payload.labels) {\n                    this.onInput(this.msg.payload);\n                }\n            }\n        },\n\n        mounted() {\n            let interval = setInterval(() => {\n                if (window.Chart) {\n                    clearInterval(interval);\n                    this.draw();\n                    this.isChartLoaded = true;\n                }\n            }, 100);\n        },\n\n        methods: {\n            draw() {\n                const ctx = this.$refs.meterchart0;\n                const chart = new Chart(ctx, {\n                    type: 'bar',\n                    data: {\n                        labels: [],\n                        datasets: [\n                            {\n                                label: 'Tesla - From Grid',\n                                data: [],\n                                backgroundColor: \"lightblue\",\n                                stack: 'tesla'\n                            },\n                            {\n                                label: 'Meter - From Grid',\n                                data: [],\n                                backgroundColor: \"red\",\n                                stack: 'meter'\n                            },\n                            {\n                                label: 'Tesla - To Grid',\n                                data: [],\n                                backgroundColor: \"orange\",\n                                stack: 'tesla'\n                            },\n                            {\n                                label: 'Meter - To Grid',\n                                data: [],\n                                backgroundColor: \"green\",\n                                stack: 'meter'\n                            }\n                        ]\n                    },\n                    options: {\n                        maintainAspectRatio: false,\n                        animation: false,\n                        responsive: true,\n                        plugins: {\n                            legend: {\n                                position: 'top',\n                            },\n                            title: {\n                                display: true,\n                                text: 'Tesla vs Meter - Injected data'\n                            }\n                        },\n                        scales: {\n                            x: {\n                                stacked: true,\n                            },\n                            y: {\n                                type: 'linear',\n                                display: true,\n                                position: 'left'\n                            }\n                        }\n                    },\n                });\n\n                this.chart = chart;\n            },\n\n            onInput(inputData) {\n                if (!inputData || !Array.isArray(inputData.labels)) return;\n\n                this.dataSets = this.chart.data.datasets;\n\n                // Clear previous data\n                this.dataSets.forEach(dataset => dataset.data = []);\n                this.chart.data.labels = [];\n\n                // Assign new data directly from arrays\n                this.chart.data.labels = inputData.labels;\n                this.dataSets[0].data = inputData.teslaFromGrid;\n                this.dataSets[1].data = inputData.meterFromGrid;\n                this.dataSets[2].data = inputData.teslaToGrid;\n                this.dataSets[3].data = inputData.meterToGrid;\n\n                this.updateChart();\n            },\n\n            updateChart() {\n                if (this.chart) {\n                    this.dataSets.forEach((element, index) => {\n                        this.chart.data.datasets[index].data = element.data;\n                    });\n                    this.chart.update();\n                }\n            },\n\n            clearChart() {\n                if (this.dataSets.length > 0) {\n                    this.dataSets.forEach(element => element.data = []);\n                    this.updateChart();\n                }\n            }\n        }\n    }\n</script>\n\n<style>\n  .base-container {\n    width: 100%;\n    height: 100%;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    container: chat / size;\n  }\n\n  .chart-container {\n    position: relative;\n    margin: auto;\n    height: 100cqb;\n    width: 100cqi;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n  }\n</style>","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":670.6471252441406,"y":395.3216857910156,"wires":[["ea6162aff0119e33"]]},{"id":"8dc54484cd9c7e23","type":"inject","z":"3d460c91742c0584","name":"Updated Meter Data (w/payload2)","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"labels\":[\"2025-07-15\",\"2025-07-16\",\"2025-07-17\",\"2025-07-18\",\"2025-07-19\",\"2025-07-20\",\"2025-07-21\",\"2025-07-22\",\"2025-07-23\",\"2025-07-24\",\"2025-07-25\",\"2025-07-26\",\"2025-07-27\",\"2025-07-28\",\"2025-07-29\",\"2025-07-30\",\"2025-07-31\",\"2025-08-01\"],\"teslaFromGrid\":[60.548,104.488,88.566,114.282,73.648,63.928,64.604,66.062,66.962,66.876,65.488,67.96,99.938,96.71,106.704,110.692,113.876,105.47],\"meterFromGrid\":[30.869,44.852,28.843,54.751,13.73,0.943,4.668,6.118,7.03,6.928,5.534,8.028,40.279,37.037,47.157,51.154,54.372,45.84],\"teslaToGrid\":[-0.11,-0.07,-0.045,-0.024,-16.551,-9.227,-4.552,-10.018,-4.244,-9.096,-2.726,-0.091,-0.063,-0.076,-0.074,-0.066,-0.057,-0.065],\"meterToGrid\":[-0.201,-0.154,-0.1,-0.068,-16.757,-9.393,-4.664,-10.154,-4.358,-9.246,-2.804,-0.162,-0.113,-0.122,-0.126,-0.083,-0.074,-0.07]}","payloadType":"json","x":379.8345642089844,"y":470.82720947265625,"wires":[["8e254e2bad333e5c"]]},{"id":"ea6162aff0119e33","type":"debug","z":"3d460c91742c0584","name":"Output debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":911.6471252441406,"y":396.8106384277344,"wires":[]},{"id":"5cd7a2a79d14beb5","type":"ui-group","name":"Tesla vs Meter - Testing","page":"8d56444ee1e5169e","width":"22","height":"10","order":1,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"8d56444ee1e5169e","type":"ui-page","name":"New Page for Testing","ui":"de5759a313e7ad79","path":"/page21","icon":"home","layout":"grid","theme":"e4b50d7892c4eb32","breakpoints":[{"name":"Default","px":"0","cols":"3"},{"name":"Tablet","px":"576","cols":"6"},{"name":"Small Desktop","px":"768","cols":"9"},{"name":"Desktop","px":"1024","cols":"12"}],"order":22,"className":"","visible":"true","disabled":"false"},{"id":"de5759a313e7ad79","type":"ui-base","name":"Node-RED Dashboard","path":"/dashboard","appIcon":"","includeClientData":false,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false,"headerContent":"dashboard","navigationStyle":"fixed","titleBarStyle":"default","showReconnectNotification":true,"notificationDisplayTime":5,"showDisconnectNotification":true,"allowInstall":true},{"id":"e4b50d7892c4eb32","type":"ui-theme","name":"Default Theme","colors":{"surface":"#ffffff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"12px","groupGap":"12px","groupBorderRadius":"4px","widgetGap":"12px","density":"default"}}]

Below is the code for ui-template:

ui-template configuration:
<template>
  <div class="base-container">
    <div class="chart-container"><canvas ref="meterchart0" /></div>
  </div>
</template>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<script>
  export default {        
        data() {
            return {
                isChartLoaded: false,
                dataSets: [],
            }
        },

        watch: {
            msg: function () {
                if (this.isChartLoaded && this.msg.payload && this.msg.payload.labels) {
                    this.onInput(this.msg.payload);
                }
            }
        },

        mounted() {
            let interval = setInterval(() => {
                if (window.Chart) {
                    clearInterval(interval);
                    this.draw();
                    this.isChartLoaded = true;
                }
            }, 100);
        },

        methods: {
            draw() {
                const ctx = this.$refs.meterchart0;
                const chart = new Chart(ctx, {
                    type: 'bar',
                    data: {
                        labels: [],
                        datasets: [
                            {
                                label: 'Tesla - From Grid',
                                data: [],
                                backgroundColor: "lightblue",
                                stack: 'tesla'
                            },
                            {
                                label: 'Meter - From Grid',
                                data: [],
                                backgroundColor: "red",
                                stack: 'meter'
                            },
                            {
                                label: 'Tesla - To Grid',
                                data: [],
                                backgroundColor: "orange",
                                stack: 'tesla'
                            },
                            {
                                label: 'Meter - To Grid',
                                data: [],
                                backgroundColor: "green",
                                stack: 'meter'
                            }
                        ]
                    },
                    options: {
                        maintainAspectRatio: false,
                        animation: false,
                        responsive: true,
                        plugins: {
                            legend: {
                                position: 'top',
                            },
                            title: {
                                display: true,
                                text: 'Tesla vs Meter - Injected data'
                            }
                        },
                        scales: {
                            x: {
                                stacked: true,
                            },
                            y: {
                                type: 'linear',
                                display: true,
                                position: 'left'
                            }
                        }
                    },
                });

                this.chart = chart;
            },

            onInput(inputData) {
                if (!inputData || !Array.isArray(inputData.labels)) return;

                this.dataSets = this.chart.data.datasets;

                // Clear previous data
                this.dataSets.forEach(dataset => dataset.data = []);
                this.chart.data.labels = [];

                // Assign new data directly from arrays
                this.chart.data.labels = inputData.labels;
                this.dataSets[0].data = inputData.teslaFromGrid;
                this.dataSets[1].data = inputData.meterFromGrid;
                this.dataSets[2].data = inputData.teslaToGrid;
                this.dataSets[3].data = inputData.meterToGrid;

                this.updateChart();
            },

            updateChart() {
                if (this.chart) {
                    this.dataSets.forEach((element, index) => {
                        this.chart.data.datasets[index].data = element.data;
                    });
                    this.chart.update();
                }
            },

            clearChart() {
                if (this.dataSets.length > 0) {
                    this.dataSets.forEach(element => element.data = []);
                    this.updateChart();
                }
            }
        }
    }
</script>

<style>
  .base-container {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    container: chat / size;
  }

  .chart-container {
    position: relative;
    margin: auto;
    height: 100cqb;
    width: 100cqi;
    display: flex;
    justify-content: center;
    align-items: center;
  }
</style>

You can do almost the same in the chart node in DB2 but stacking is not an option and also, I have other charts that are a mix of line/bar charts, hence the dive into chart.js

I hope this helps someone. Again - thank you @Buckskin and @hotNipi . Could not have done this without your help :folded_hands:t3:

Sample Output

1 Like