Issue Integrating Chart.js with Node-RED Dashboard 2.0 (Vue-based Template Node)

Hello everyone,

I'm currently facing an issue trying to integrate Chart.js with Node-RED Dashboard 2.0 using a Vue-based template node. I am hoping to see if anyone has successfully managed to do this or can provide some insight into what might be going wrong.

Function node

[
    {
        "id": "7a657a2e71c54594",
        "type": "function",
        "z": "5df899d3ab0f31cc",
        "name": "function 3",
        "func": "// Parse and convert the Timestamp to a readable format for the chart\nconst timestamp = new Date(msg.payload.Timestamp).toLocaleTimeString(); // Using locale time string for the chart labels\n\n// Extract signals and parse values\nconst signals = msg.payload.Signals;\n\n// Extract speed values\nconst spd1 = parseFloat(signals.SPD1.replace(\" MPH\", \"\"));\nconst spd2 = parseFloat(signals.SPD2.replace(\" MPH\", \"\"));\nconst spd3 = parseFloat(signals.SPD3.replace(\" MPH\", \"\"));\nconst spd4 = parseFloat(signals.SPD4.replace(\" MPH\", \"\"));\nconst avgSpeed = (spd1 + spd2 + spd3 + spd4) / 4;  // Calculate average speed\n\n// Extract notch position\nconst notch = parseFloat(signals.ENOT.replace(\" #\", \"\")); // Assuming ENOT represents the notch position\n\n// Create a consolidated payload\nlet chartData = {\n    timestamp: timestamp,\n    speed: avgSpeed,\n    notch: notch\n};\n\n// Send the consolidated chart data as a single message\nmsg.payload = chartData;\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 180,
        "wires": [
            [
                "d078fa1f2b310b3b"
            ]
        ]
    },
    {
        "id": "a698fe0322fa9d06",
        "type": "inject",
        "z": "5df899d3ab0f31cc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"Timestamp\":\"2024-11-14T22:44:31.5038441Z\",\"CarNumber\":null,\"Signals\":{\"13T\":\"1\",\"ac0\":\"1\",\"AFCO\":\"2.7 PSI\",\"ag10\":\"0\",\"ag11\":\"0\",\"ag4\":\"0\",\"ag5\":\"0\",\"ag6\":\"0\",\"ag7\":\"0\",\"ag8\":\"0\",\"ag9\":\"0\",\"ai100\":\"0\",\"ai101\":\"0\",\"ai102\":\"0\",\"ai103\":\"0\",\"ai104\":\"0\",\"ai105\":\"0\",\"ai41\":\"0\",\"ai42\":\"0\",\"ai43\":\"0\",\"ai44\":\"0\",\"ai45\":\"0\",\"ai46\":\"0\",\"ai47\":\"0\",\"ai48\":\"0\",\"ai49\":\"0\",\"ai50\":\"0\",\"ai51\":\"0\",\"ai52\":\"0\",\"ai53\":\"0\",\"ai54\":\"0\",\"ai55\":\"-3\",\"ai56\":\"0\",\"ai57\":\"0\",\"ai58\":\"0\",\"ai59\":\"0\",\"ai60\":\"0\",\"ai61\":\"0\",\"ai62\":\"-12\",\"ai63\":\"0\",\"ai64\":\"0\",\"ai65\":\"0\",\"ai66\":\"0\",\"ai67\":\"5584\",\"ai68\":\"-130\",\"ai69\":\"-2549\",\"ai70\":\"-3656\",\"ai71\":\"5584\",\"ai72\":\"-130\",\"ai73\":\"-2549\",\"ai74\":\"-3656\",\"ai75\":\"0\",\"ai76\":\"0\",\"ai77\":\"-20\",\"ai78\":\"67\",\"ai79\":\"-10\",\"ai80\":\"-44\",\"ai81\":\"-24\",\"ai82\":\"64\",\"ai83\":\"-14\",\"ai84\":\"-47\",\"ai85\":\"0\",\"ai86\":\"1\",\"ai87\":\"-1\",\"ai88\":\"0\",\"ai89\":\"0\",\"ai90\":\"0\",\"ai91\":\"0\",\"ai92\":\"0\",\"ai93\":\"129\",\"ai94\":\"0\",\"ai95\":\"0\",\"ai96\":\"0\",\"ai97\":\"0\",\"ai98\":\"0\",\"ai99\":\"0\",\"ALM\":\"0\",\"ALMS\":\"0\",\"AMBC\":\"98.75 %\",\"AMBT\":\"79.3 F\",\"AUX\":\"0\",\"AVMU\":\"0\",\"B\":\"0\",\"BAR\":\"15.0 PSI\",\"BARC\":\"100.54 %\",\"BATI\":\"-12 A\",\"BATV\":\"64 V\",\"BBI\":\"0 A\",\"BBLR\":\"0\",\"BBR\":\"0 #\",\"BCT1\":\"0 A\",\"BCT2\":\"0 A\",\"BCT3\":\"0 A\",\"BLD\":\"0\",\"BMT1\":\"0 A\",\"BMT2\":\"0 A\",\"BSTD\":\"0\",\"BSTP\":\"0.6 PSI\",\"BTMP\":\"132 F\",\"BVMU\":\"0\",\"BWMU\":\"0\",\"CA5\":\"0 V\",\"CALL\":\"63.3 PSI\",\"CAP\":\"0.00 V\",\"CBCP\":\"63 PSI\",\"CCP\":\"131.1 PSI\",\"CLOP\":\"0\",\"CRPM\":\"0 RPM\",\"CTHP\":\"0 HP\",\"CVMU\":\"0\",\"DB\":\"1.0 #\",\"DBCO\":\"0\",\"DBMU\":\"0\",\"DBV\":\"0 V\",\"DBX\":\"0\",\"DC1\":\"0\",\"di100\":\"0\",\"di101\":\"0\",\"di102\":\"0\",\"di103\":\"0\",\"di104\":\"0\",\"di105\":\"0\",\"di106\":\"0\",\"di107\":\"0\",\"di108\":\"0\",\"di109\":\"0\",\"di110\":\"0\",\"di111\":\"0\",\"di112\":\"1\",\"di113\":\"1\",\"di114\":\"1\",\"di115\":\"1\",\"di116\":\"1\",\"di117\":\"1\",\"di118\":\"1\",\"di119\":\"1\",\"di120\":\"1\",\"di121\":\"1\",\"di122\":\"1\",\"di123\":\"1\",\"di124\":\"1\",\"di125\":\"1\",\"di126\":\"1\",\"di127\":\"1\",\"di26\":\"0\",\"di32\":\"0\",\"di33\":\"0\",\"di36\":\"1\",\"di37\":\"1\",\"di38\":\"0\",\"di43\":\"0\",\"di54\":\"0\",\"di55\":\"1\",\"di59\":\"0\",\"di65\":\"0\",\"di69\":\"0\",\"di75\":\"0\",\"di77\":\"1\",\"di78\":\"0\",\"di82\":\"0\",\"di83\":\"0\",\"di86\":\"0\",\"di87\":\"0\",\"di96\":\"0\",\"di97\":\"0\",\"di98\":\"0\",\"di99\":\"0\",\"DLVY\":\"-1 DEG\",\"do0\":\"0\",\"do1\":\"0\",\"do10\":\"0\",\"do11\":\"0\",\"do12\":\"0\",\"do13\":\"0\",\"do15\":\"0\",\"do16\":\"0\",\"do17\":\"0\",\"do18\":\"0\",\"do19\":\"0\",\"do2\":\"0\",\"do20\":\"0\",\"do21\":\"0\",\"do22\":\"0\",\"do23\":\"0\",\"do25\":\"0\",\"do26\":\"0\",\"do27\":\"0\",\"do28\":\"0\",\"do29\":\"0\",\"do30\":\"0\",\"do33\":\"0\",\"do34\":\"0\",\"do35\":\"0\",\"do36\":\"0\",\"do37\":\"0\",\"do38\":\"0\",\"do4\":\"0\",\"do40\":\"0\",\"do41\":\"0\",\"do42\":\"0\",\"do43\":\"1\",\"do44\":\"0\",\"do45\":\"0\",\"do46\":\"0\",\"do47\":\"0\",\"do48\":\"0\",\"do49\":\"0\",\"do5\":\"0\",\"do50\":\"0\",\"do51\":\"0\",\"do52\":\"0\",\"do53\":\"0\",\"do54\":\"0\",\"do55\":\"0\",\"do56\":\"0\",\"do57\":\"0\",\"do58\":\"0\",\"do59\":\"0\",\"do6\":\"0\",\"do60\":\"0\",\"do61\":\"0\",\"do62\":\"0\",\"do63\":\"0\",\"do7\":\"0\",\"do8\":\"0\",\"do9\":\"0\",\"du0\":\"26\",\"du1\":\"0\",\"du10\":\"0\",\"du11\":\"0\",\"du12\":\"0\",\"du13\":\"0\",\"du14\":\"3\",\"du15\":\"0\",\"du16\":\"0\",\"du17\":\"0\",\"du2\":\"0\",\"du3\":\"0\",\"du4\":\"0\",\"du5\":\"0\",\"du6\":\"0\",\"du7\":\"0\",\"du8\":\"0\",\"du9\":\"0\",\"DVM1\":\"-0.2 V\",\"DVM2\":\"0.0 V\",\"DVMU\":\"0\",\"EBST\":\"0.1 PSI\",\"EFCO\":\"1\",\"EFF\":\"63.9 PSI\",\"EFS\":\"0\",\"ENOT\":\"2 #\",\"EPBY\":\"0\",\"EPC\":\"0\",\"EPS\":\"0\",\"ERMU\":\"0\",\"ERPM\":\"0 RPM\",\"ERUN\":\"0\",\"ESPD\":\"0.0 MPH\",\"ESS\":\"0\",\"FC1\":\"0\",\"FC2\":\"0\",\"FC3\":\"0\",\"FCON\":\"0.0 GPH\",\"FLTR\":\"0 V\",\"FMU\":\"0\",\"FPC\":\"0\",\"FPCR\":\"1\",\"FPRM\":\"1\",\"FPSI\":\"0 PSI\",\"FTMP\":\"116 F\",\"FULC\":\"97.18 %\",\"FVS\":\"0\",\"GCR\":\"1\",\"GFA\":\"0.0 A\",\"GFC\":\"0\",\"GFD\":\"0\",\"GFMU\":\"0\",\"GR\":\"0\",\"GRCO\":\"1\",\"GRDB\":\"0 #\",\"GRPR\":\"0 #\",\"HEPF\":\"0\",\"HIDL\":\"0\",\"IAIR\":\"82 F\",\"KLBS\":\"0 KLBs\",\"LDSG\":\"0.0 %\",\"LR\":\"100.0 %\",\"LTT1\":\"0\",\"LTT2\":\"0\",\"MBP1\":\"0\",\"MBP2\":\"0\",\"MBP3\":\"0\",\"MBP4\":\"0\",\"MCO1\":\"0\",\"MCO2\":\"0\",\"MCO3\":\"0\",\"MCO4\":\"0\",\"MGA\":\"0 A\",\"MGV\":\"0 V\",\"mi22\":\"1\",\"mi7\":\"0\",\"mi9\":\"0\",\"MNOT\":\"0 #\",\"MR2\":\"131.2 PSI\",\"MSND\":\"0\",\"MVCC\":\"0\",\"MVH\":\"0\",\"MVR\":\"0\",\"MVSF\":\"0\",\"MVSH\":\"1\",\"MVSR\":\"0\",\"NPRO\":\"0\",\"OILP\":\"0 PSI\",\"OILT\":\"163.6 F\",\"P1\":\"0\",\"P2\":\"0\",\"P3\":\"0\",\"P4\":\"0\",\"PA\":\"1\",\"PCR\":\"1\",\"RMU\":\"0\",\"RPMR\":\"270 RPM\",\"RUN\":\"0\",\"RVF1\":\"0\",\"RVF2\":\"0\",\"RVR3\":\"0\",\"RVR4\":\"0\",\"SE\":\"0 #\",\"SHED\":\"0\",\"SPD\":\"0 MPH\",\"SPD1\":\"20.00 MPH\",\"SPD2\":\"20.00 MPH\",\"SPD3\":\"20.00 MPH\",\"SPD4\":\"20.00 MPH\",\"SSPD\":\"0 V\",\"STAO\":\"0\",\"STRT\":\"12 A\",\"TBKR\":\"1\",\"td0\":\"24\",\"td1\":\"11\",\"td2\":\"7\",\"td3\":\"17\",\"td4\":\"12\",\"td5\":\"17\",\"td6\":\"70\",\"td7\":\"255\",\"TH\":\"0.00 V\",\"THP\":\"0 HP\",\"TLP\":\"1\",\"TM1\":\"0 A\",\"TM2\":\"0 A\",\"TM3\":\"0 A\",\"TM4\":\"0 A\",\"TMI\":\"0 A\",\"TMT\":\"23 C\",\"TNOT\":\"0 #\",\"WAT1\":\"158 F\",\"WAT2\":\"158 F\",\"WSC\":\"0.00 V\",\"WSMU\":\"0\",\"WTRI\":\"3 PSI\",\"WTRO\":\"3 PSI\",\"ZSPD\":\"0\"}}",
        "payloadType": "json",
        "x": 130,
        "y": 180,
        "wires": [
            [
                "7a657a2e71c54594"
            ]
        ]
    },
    {
        "id": "d078fa1f2b310b3b",
        "type": "ui-template",
        "z": "5df899d3ab0f31cc",
        "group": "907fd2144025ed7a",
        "page": "",
        "ui": "",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "head": "",
        "format": "<template>\n  <div>\n    <h2>Speed vs Notch Position</h2>\n    <canvas id=\"myChart\"></canvas>\n  </div>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      chart: null,\n      chartData: {\n        labels: [], // X-axis labels (e.g., timestamps)\n        datasets: [\n          {\n            label: 'Speed',\n            data: [], // Speed data\n            borderColor: 'rgba(75, 192, 192, 1)',\n            backgroundColor: 'rgba(75, 192, 192, 0.2)',\n            yAxisID: 'y-axis-speed',\n          },\n          {\n            label: 'Notch Position',\n            data: [], // Notch position data\n            borderColor: 'rgba(153, 102, 255, 1)',\n            backgroundColor: 'rgba(153, 102, 255, 0.2)',\n            yAxisID: 'y-axis-notch',\n          },\n        ],\n      },\n      chartOptions: {\n        responsive: true,\n        scales: {\n          'y-axis-speed': {\n            type: 'linear',\n            position: 'left',\n            title: {\n              display: true,\n              text: 'Speed (MPH)',\n            },\n          },\n          'y-axis-notch': {\n            type: 'linear',\n            position: 'right',\n            title: {\n              display: true,\n              text: 'Notch Position',\n            },\n            grid: {\n              drawOnChartArea: false, // Keep grid lines separate\n            },\n          },\n          x: {\n            type: 'category', // Suitable for timestamps\n            title: {\n              display: true,\n              text: 'Time',\n            },\n          },\n        },\n      },\n    };\n  },\n  mounted() {\n    // Load Chart.js from CDN\n    const script = document.createElement('script');\n    script.src = 'https://cdn.jsdelivr.net/npm/chart.js';\n    script.onload = () => {\n      const ctx = document.getElementById('myChart').getContext('2d');\n      this.chart = new Chart(ctx, {\n        type: 'line',\n        data: this.chartData,\n        options: this.chartOptions,\n      });\n    };\n    document.head.appendChild(script);\n  },\n  methods: {\n    updateChart(msg) {\n      if (msg && msg.payload) {\n        console.log('New payload received:', msg.payload); // Debugging line\n\n        // Extract the new values from the payload\n        const { timestamp, speed, notch } = msg.payload;\n\n        // Check if the values are valid\n        if (timestamp && speed !== undefined && notch !== undefined) {\n          // Add the new timestamp to the labels\n          this.chartData.labels.push(timestamp);\n\n          // Add the new speed and notch values to the datasets\n          this.chartData.datasets[0].data.push(speed);\n          this.chartData.datasets[1].data.push(notch);\n\n          // Keep the data array length reasonable to avoid performance issues\n          if (this.chartData.labels.length > 50) {\n            this.chartData.labels.shift();\n            this.chartData.datasets[0].data.shift();\n            this.chartData.datasets[1].data.shift();\n          }\n\n          // Update the chart with the new data\n          if (this.chart) {\n            console.log('Updating chart with new data'); // Debugging line\n            this.chart.update();\n          }\n        } else {\n          console.error('Invalid payload data:', msg.payload); // Debugging line\n        }\n      }\n    },\n  },\n  watch: {\n    msg: {\n      handler(newMsg) {\n        this.updateChart(newMsg);\n      },\n      immediate: true, // Trigger the handler immediately with the current value of msg\n    },\n  },\n};\n</script>\n\n<style>\n#myChart {\n  max-width: 100%;\n  max-height: 400px;\n}\n</style>\n",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 580,
        "y": 180,
        "wires": [
            [
                "0b1f9eab6a56695a"
            ]
        ]
    },
    {
        "id": "0b1f9eab6a56695a",
        "type": "debug",
        "z": "5df899d3ab0f31cc",
        "name": "debug 3",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 820,
        "y": 180,
        "wires": []
    },
    {
        "id": "907fd2144025ed7a",
        "type": "ui-group",
        "name": "Group_analysis_chart",
        "page": "2e71a815369cbeff",
        "width": "6",
        "height": "1",
        "order": 2,
        "showTitle": false,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "2e71a815369cbeff",
        "type": "ui-page",
        "name": "Live Analysis",
        "ui": "59dc26b2539761ad",
        "path": "/locomotive-dashboard/analysis",
        "icon": "mdi-chart-line",
        "layout": "grid",
        "theme": "def1340b62de71d6",
        "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": 2,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "59dc26b2539761ad",
        "type": "ui-base",
        "name": "UI Name",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-control",
            "ui-chart",
            "ui-gauge"
        ],
        "showPathInSidebar": false,
        "showPageTitle": true,
        "navigationStyle": "default",
        "titleBarStyle": "default"
    },
    {
        "id": "def1340b62de71d6",
        "type": "ui-theme",
        "name": "Default Theme",
        "colors": {
            "surface": "#272626",
            "primary": "#262626",
            "bgPage": "#262626",
            "groupBg": "#262626",
            "groupOutline": "#262626"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    }
]

Has anyone successfully integrated Chart.js into Node-RED Dashboard 2.0 with Vue.js template nodes?

Here's 2 working charts with static data. Examine those to find out what is different in buildup.
Your code for updating the chart seems fine ...

[{"id":"ae617d118b80c0d8","type":"ui-template","z":"9ab81d258b54a577","group":"2c34b9c7d6324531","page":"","ui":"","name":"Floating bar chart","order":5,"width":"6","height":"6","head":"","format":"<template>\n    <div class=\"base-container\">\n        <div class=\"chart-container\"><canvas ref=\"floatingbarchart\" /></div>\n    </div>\n</template>\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n<script>\n    export default {        \n        data() {\n            return {               \n            }\n        },\n        computed: {\n            \n        },\n        mounted() {\n            this.$socket.on('msg-input:' + this.id, this.onInput)\n            let interval = setInterval(() => {\n                if (window.Chart) {\n                    clearInterval(interval);\n                    this.draw()\n                }\n            }, 100);\n        },\n        methods: {\n            draw () {\n                const ctx = this.$refs.floatingbarchart\n                const chart = new Chart(ctx, {\n                    type: 'bar',                    \n                    data: {\n                        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n                        datasets: [                            \n                            {\n                                label: 'Water stuff',\n                                data:[[0,4.9],[0,3.9],[0,3.5],[0,3.4],[0,4.2],[0,7.0],[0,6.7],[0,8.1],[0,5.8],[0,7.2],[0,6.1],[0,5.3]], \n                                backgroundColor: \"lightblue\" ,\n                                yAxisID: 'y1'\n                            },\n                            {\n                                label: 'Temperature',\n                                data:[[10.1,-35.0],[10.1,-27.8],[18.4,-15.8],[27.6,-6.7],[33.1,-2.5],[32.4,0.5],[35.2,0.2],[35.6,-5.2],[30.2,-17.0],[22.2,-25.9],[14.3,-34.6],[12.5,-34.6]], \n                                backgroundColor: \"orange\", \n                                yAxisID: 'y'\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: 'Floating bar chart'\n                            }\n                        },\n                        scales: {\n                            x: {\n                                stacked: false,\n                            },\n                            y:{\n                                type: 'linear',\n                                display: true,\n                                position: 'right'\n                            },\n                            y1:{\n                                type: 'linear',\n                                display: true,\n                                position: 'left',                                \n                                grid: {\n                                    drawOnChartArea: false \n                                }\n                            }\n                        }\n                    },\n                });\n                this.chart = chart                \n            }\n        }\n    }\n\n\n    \n</script>\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>\n","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":670,"y":1740,"wires":[[]]},{"id":"7e6c8c2d1df4a960","type":"ui-template","z":"9ab81d258b54a577","group":"2c34b9c7d6324531","page":"","ui":"","name":"fancyarea","order":6,"width":"6","height":"6","head":"","format":"<template>\n    <div class=\"base-container\">\n        <div class=\"chart-container\"><canvas ref=\"uniqueChart\" /></div>\n    </div>\n</template>\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n<script>\n    export default {        \n        data() {\n            return {                               \n            }\n        },\n        computed: {\n            \n        },\n        mounted() {\n            this.$socket.on('msg-input:' + this.id, this.onInput)\n            let interval = setInterval(() => {\n                if (window.Chart) {\n                    clearInterval(interval);\n                    this.draw()\n                }\n            }, 100);\n        },\n        methods: {\n            draw () {\n                const ctx = this.$refs.uniqueChart\n                const gradient = ctx.getContext(\"2d\").createLinearGradient(0, 0, 0, 400);\n                gradient.addColorStop(0, 'rgba(250,174,50,0.5)');   \n                gradient.addColorStop(0.5, 'rgba(250,174,50,0)');\n                const chart = new Chart(ctx, {\n                    type: 'line',                    \n                    data: {\n                        labels: [1,2,3,4,5,6],\n                        datasets: [                            \n                            {                                \n                                data:[3.5,4.7,3.1,5.2,4.3,5.1], \n                                backgroundColor: gradient,\n                                borderWidth:1,                              \n                                fill: 'start' ,\n                                pointRadius: 0,\n                                cubicInterpolationMode: 'monotone',\n                                tension: 0.4\n                               \n                            }                      \n                        ]\n                    },\n                    options: {                        \n                        maintainAspectRatio: false,\n                        animation: false,\n                        responsive: true, \n                        plugins: {\n                            legend: {\n                                display: true,\n                            },\n                            title: {\n                                display: true,\n                               \n                            }\n                        },\n                        scales: {\n                            x:{\n                                display:true\n                            },\n                            y:{\n                                display:true,\n                                min: 0,\n                            }\n                        }\n                    },\n                });\n                this.chart = chart                \n            }\n        }\n    }\n\n\n    \n</script>\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>\n","storeOutMessages":true,"passthru":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":640,"y":1780,"wires":[[]]},{"id":"2c34b9c7d6324531","type":"ui-group","name":"Devices","page":"7294756f31e17b81","width":"6","height":"1","order":2,"showTitle":true,"className":"","visible":"true","disabled":"false","groupType":"default"},{"id":"7294756f31e17b81","type":"ui-page","name":"Home","ui":"29792df7d7b05e2e","path":"/home","icon":"home","layout":"grid","theme":"52ba8a01d6eda628","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":5,"className":"","visible":true,"disabled":false},{"id":"29792df7d7b05e2e","type":"ui-base","name":"My Dashboard","path":"/dashboard","appIcon":"","includeClientData":false,"acceptsClientConfig":[],"showPathInSidebar":false,"showPageTitle":true,"navigationStyle":"default","titleBarStyle":"default"},{"id":"52ba8a01d6eda628","type":"ui-theme","name":"Mobile","colors":{"surface":"#ffffff","primary":"#0094ce","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"density":"compact","pagePadding":"5px","groupGap":"5px","groupBorderRadius":"10px","widgetGap":"5px"}}]

Thank you for providing the example code! I appreciate your help. I had a few questions regarding the real-time data aspect of my requirement.

In my use case, I'm working with real-time data that updates every 500ms. I noticed that in the provided solution:

  1. The chart data (labels and datasets) is hardcoded in the draw() method, and there's no mechanism for listening to a payload or receiving updates.
  2. There is a socket listener (this.$socket.on('msg-input:' + this.id, this.onInput)), but I can't see any code that handles dynamic updates. For my project, the chart needs to update continuously as new data arrives in the form of a JSON payload.

Would you have any suggestions for:

  • Handling real-time data input from a payload or socket?
  • Updating the chart dynamically as new data arrives, rather than drawing a static chart?

Thank you!

Here is an example with live data. But for sure not complete solution. Just as an example of how to...

Why? Humans can't analyse the outcome that fast.

1 Like

"Hahaha, thank you for pointing that out! The 500ms update rate is mainly for capturing real-time data accurately—it may not be something a human can analyze that quickly, but it helps with monitoring and recording purposes.

Unfortunately, I'm still facing issues with getting the chart to work correctly. I have the payload being injected, but the chart doesn't seem to process the data properly. Your example works perfectly on its own, but when I try to adapt it exactly to my setup, it fails to update or display any data.

Here is my code for reference, in case you can spot anything that I might be missing:

[
    {
        "id": "7a657a2e71c54594",
        "type": "function",
        "z": "5df899d3ab0f31cc",
        "name": "function 3",
        "func": "const timestamp = new Date().getTime();\nconst spd1 = 0;\nconst spd2 = 0;\nconst spd3 = 0;\nconst spd4 = 0;\n\nlet messages = [\n    { payload: { time: timestamp, value: spd1 }, topic: \"SPD1\" },\n    { payload: { time: timestamp, value: spd2 }, topic: \"SPD2\" },\n    { payload: { time: timestamp, value: spd3 }, topic: \"SPD3\" },\n    { payload: { time: timestamp, value: spd4 }, topic: \"SPD4\" }\n];\n\nreturn [messages];\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 340,
        "y": 180,
        "wires": [
            [
                "d078fa1f2b310b3b"
            ]
        ]
    },
    {
        "id": "a698fe0322fa9d06",
        "type": "inject",
        "z": "5df899d3ab0f31cc",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"Timestamp\":\"2024-11-14T22:44:31.5038441Z\",\"CarNumber\":null,\"Signals\":{\"13T\":\"1\",\"ac0\":\"1\",\"AFCO\":\"2.7 PSI\",\"ag10\":\"0\",\"ag11\":\"0\",\"ag4\":\"0\",\"ag5\":\"0\",\"ag6\":\"0\",\"ag7\":\"0\",\"ag8\":\"0\",\"ag9\":\"0\",\"ai100\":\"0\",\"ai101\":\"0\",\"ai102\":\"0\",\"ai103\":\"0\",\"ai104\":\"0\",\"ai105\":\"0\",\"ai41\":\"0\",\"ai42\":\"0\",\"ai43\":\"0\",\"ai44\":\"0\",\"ai45\":\"0\",\"ai46\":\"0\",\"ai47\":\"0\",\"ai48\":\"0\",\"ai49\":\"0\",\"ai50\":\"0\",\"ai51\":\"0\",\"ai52\":\"0\",\"ai53\":\"0\",\"ai54\":\"0\",\"ai55\":\"-3\",\"ai56\":\"0\",\"ai57\":\"0\",\"ai58\":\"0\",\"ai59\":\"0\",\"ai60\":\"0\",\"ai61\":\"0\",\"ai62\":\"-12\",\"ai63\":\"0\",\"ai64\":\"0\",\"ai65\":\"0\",\"ai66\":\"0\",\"ai67\":\"5584\",\"ai68\":\"-130\",\"ai69\":\"-2549\",\"ai70\":\"-3656\",\"ai71\":\"5584\",\"ai72\":\"-130\",\"ai73\":\"-2549\",\"ai74\":\"-3656\",\"ai75\":\"0\",\"ai76\":\"0\",\"ai77\":\"-20\",\"ai78\":\"67\",\"ai79\":\"-10\",\"ai80\":\"-44\",\"ai81\":\"-24\",\"ai82\":\"64\",\"ai83\":\"-14\",\"ai84\":\"-47\",\"ai85\":\"0\",\"ai86\":\"1\",\"ai87\":\"-1\",\"ai88\":\"0\",\"ai89\":\"0\",\"ai90\":\"0\",\"ai91\":\"0\",\"ai92\":\"0\",\"ai93\":\"129\",\"ai94\":\"0\",\"ai95\":\"0\",\"ai96\":\"0\",\"ai97\":\"0\",\"ai98\":\"0\",\"ai99\":\"0\",\"ALM\":\"0\",\"ALMS\":\"0\",\"AMBC\":\"98.75 %\",\"AMBT\":\"79.3 F\",\"AUX\":\"0\",\"AVMU\":\"0\",\"B\":\"0\",\"BAR\":\"15.0 PSI\",\"BARC\":\"100.54 %\",\"BATI\":\"-12 A\",\"BATV\":\"64 V\",\"BBI\":\"0 A\",\"BBLR\":\"0\",\"BBR\":\"0 #\",\"BCT1\":\"0 A\",\"BCT2\":\"0 A\",\"BCT3\":\"0 A\",\"BLD\":\"0\",\"BMT1\":\"0 A\",\"BMT2\":\"0 A\",\"BSTD\":\"0\",\"BSTP\":\"0.6 PSI\",\"BTMP\":\"132 F\",\"BVMU\":\"0\",\"BWMU\":\"0\",\"CA5\":\"0 V\",\"CALL\":\"63.3 PSI\",\"CAP\":\"0.00 V\",\"CBCP\":\"63 PSI\",\"CCP\":\"131.1 PSI\",\"CLOP\":\"0\",\"CRPM\":\"0 RPM\",\"CTHP\":\"0 HP\",\"CVMU\":\"0\",\"DB\":\"1.0 #\",\"DBCO\":\"0\",\"DBMU\":\"0\",\"DBV\":\"0 V\",\"DBX\":\"0\",\"DC1\":\"0\",\"di100\":\"0\",\"di101\":\"0\",\"di102\":\"0\",\"di103\":\"0\",\"di104\":\"0\",\"di105\":\"0\",\"di106\":\"0\",\"di107\":\"0\",\"di108\":\"0\",\"di109\":\"0\",\"di110\":\"0\",\"di111\":\"0\",\"di112\":\"1\",\"di113\":\"1\",\"di114\":\"1\",\"di115\":\"1\",\"di116\":\"1\",\"di117\":\"1\",\"di118\":\"1\",\"di119\":\"1\",\"di120\":\"1\",\"di121\":\"1\",\"di122\":\"1\",\"di123\":\"1\",\"di124\":\"1\",\"di125\":\"1\",\"di126\":\"1\",\"di127\":\"1\",\"di26\":\"0\",\"di32\":\"0\",\"di33\":\"0\",\"di36\":\"1\",\"di37\":\"1\",\"di38\":\"0\",\"di43\":\"0\",\"di54\":\"0\",\"di55\":\"1\",\"di59\":\"0\",\"di65\":\"0\",\"di69\":\"0\",\"di75\":\"0\",\"di77\":\"1\",\"di78\":\"0\",\"di82\":\"0\",\"di83\":\"0\",\"di86\":\"0\",\"di87\":\"0\",\"di96\":\"0\",\"di97\":\"0\",\"di98\":\"0\",\"di99\":\"0\",\"DLVY\":\"-1 DEG\",\"do0\":\"0\",\"do1\":\"0\",\"do10\":\"0\",\"do11\":\"0\",\"do12\":\"0\",\"do13\":\"0\",\"do15\":\"0\",\"do16\":\"0\",\"do17\":\"0\",\"do18\":\"0\",\"do19\":\"0\",\"do2\":\"0\",\"do20\":\"0\",\"do21\":\"0\",\"do22\":\"0\",\"do23\":\"0\",\"do25\":\"0\",\"do26\":\"0\",\"do27\":\"0\",\"do28\":\"0\",\"do29\":\"0\",\"do30\":\"0\",\"do33\":\"0\",\"do34\":\"0\",\"do35\":\"0\",\"do36\":\"0\",\"do37\":\"0\",\"do38\":\"0\",\"do4\":\"0\",\"do40\":\"0\",\"do41\":\"0\",\"do42\":\"0\",\"do43\":\"1\",\"do44\":\"0\",\"do45\":\"0\",\"do46\":\"0\",\"do47\":\"0\",\"do48\":\"0\",\"do49\":\"0\",\"do5\":\"0\",\"do50\":\"0\",\"do51\":\"0\",\"do52\":\"0\",\"do53\":\"0\",\"do54\":\"0\",\"do55\":\"0\",\"do56\":\"0\",\"do57\":\"0\",\"do58\":\"0\",\"do59\":\"0\",\"do6\":\"0\",\"do60\":\"0\",\"do61\":\"0\",\"do62\":\"0\",\"do63\":\"0\",\"do7\":\"0\",\"do8\":\"0\",\"do9\":\"0\",\"du0\":\"26\",\"du1\":\"0\",\"du10\":\"0\",\"du11\":\"0\",\"du12\":\"0\",\"du13\":\"0\",\"du14\":\"3\",\"du15\":\"0\",\"du16\":\"0\",\"du17\":\"0\",\"du2\":\"0\",\"du3\":\"0\",\"du4\":\"0\",\"du5\":\"0\",\"du6\":\"0\",\"du7\":\"0\",\"du8\":\"0\",\"du9\":\"0\",\"DVM1\":\"-0.2 V\",\"DVM2\":\"0.0 V\",\"DVMU\":\"0\",\"EBST\":\"0.1 PSI\",\"EFCO\":\"1\",\"EFF\":\"63.9 PSI\",\"EFS\":\"0\",\"ENOT\":\"2 #\",\"EPBY\":\"0\",\"EPC\":\"0\",\"EPS\":\"0\",\"ERMU\":\"0\",\"ERPM\":\"0 RPM\",\"ERUN\":\"0\",\"ESPD\":\"0.0 MPH\",\"ESS\":\"0\",\"FC1\":\"0\",\"FC2\":\"0\",\"FC3\":\"0\",\"FCON\":\"0.0 GPH\",\"FLTR\":\"0 V\",\"FMU\":\"0\",\"FPC\":\"0\",\"FPCR\":\"1\",\"FPRM\":\"1\",\"FPSI\":\"0 PSI\",\"FTMP\":\"116 F\",\"FULC\":\"97.18 %\",\"FVS\":\"0\",\"GCR\":\"1\",\"GFA\":\"0.0 A\",\"GFC\":\"0\",\"GFD\":\"0\",\"GFMU\":\"0\",\"GR\":\"0\",\"GRCO\":\"1\",\"GRDB\":\"0 #\",\"GRPR\":\"0 #\",\"HEPF\":\"0\",\"HIDL\":\"0\",\"IAIR\":\"82 F\",\"KLBS\":\"0 KLBs\",\"LDSG\":\"0.0 %\",\"LR\":\"100.0 %\",\"LTT1\":\"0\",\"LTT2\":\"0\",\"MBP1\":\"0\",\"MBP2\":\"0\",\"MBP3\":\"0\",\"MBP4\":\"0\",\"MCO1\":\"0\",\"MCO2\":\"0\",\"MCO3\":\"0\",\"MCO4\":\"0\",\"MGA\":\"0 A\",\"MGV\":\"0 V\",\"mi22\":\"1\",\"mi7\":\"0\",\"mi9\":\"0\",\"MNOT\":\"0 #\",\"MR2\":\"131.2 PSI\",\"MSND\":\"0\",\"MVCC\":\"0\",\"MVH\":\"0\",\"MVR\":\"0\",\"MVSF\":\"0\",\"MVSH\":\"1\",\"MVSR\":\"0\",\"NPRO\":\"0\",\"OILP\":\"0 PSI\",\"OILT\":\"163.6 F\",\"P1\":\"0\",\"P2\":\"0\",\"P3\":\"0\",\"P4\":\"0\",\"PA\":\"1\",\"PCR\":\"1\",\"RMU\":\"0\",\"RPMR\":\"270 RPM\",\"RUN\":\"0\",\"RVF1\":\"0\",\"RVF2\":\"0\",\"RVR3\":\"0\",\"RVR4\":\"0\",\"SE\":\"0 #\",\"SHED\":\"0\",\"SPD\":\"0 MPH\",\"SPD1\":\"20.00 MPH\",\"SPD2\":\"20.00 MPH\",\"SPD3\":\"20.00 MPH\",\"SPD4\":\"20.00 MPH\",\"SSPD\":\"0 V\",\"STAO\":\"0\",\"STRT\":\"12 A\",\"TBKR\":\"1\",\"td0\":\"24\",\"td1\":\"11\",\"td2\":\"7\",\"td3\":\"17\",\"td4\":\"12\",\"td5\":\"17\",\"td6\":\"70\",\"td7\":\"255\",\"TH\":\"0.00 V\",\"THP\":\"0 HP\",\"TLP\":\"1\",\"TM1\":\"0 A\",\"TM2\":\"0 A\",\"TM3\":\"0 A\",\"TM4\":\"0 A\",\"TMI\":\"0 A\",\"TMT\":\"23 C\",\"TNOT\":\"0 #\",\"WAT1\":\"158 F\",\"WAT2\":\"158 F\",\"WSC\":\"0.00 V\",\"WSMU\":\"0\",\"WTRI\":\"3 PSI\",\"WTRO\":\"3 PSI\",\"ZSPD\":\"0\"}}",
        "payloadType": "json",
        "x": 130,
        "y": 180,
        "wires": [
            [
                "7a657a2e71c54594"
            ]
        ]
    },
    {
        "id": "d078fa1f2b310b3b",
        "type": "ui-template",
        "z": "5df899d3ab0f31cc",
        "group": "2c34b9c7d6324531",
        "page": "",
        "ui": "",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "head": "",
        "format": "<template>\n    <div class=\"chart-container\">\n        <canvas ref=\"chartCanvas\"></canvas>\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                chart: null  // Store the chart instance\n            };\n        },\n        mounted() {\n            this.initChart();  // Initialize chart\n            // Test updating chart with mock data every 1 second\n            setInterval(() => {\n                this.updateChart({\n                    date: Date.now(),\n                    SPD1: Math.random() * 100,\n                    SPD2: Math.random() * 100,\n                    SPD3: Math.random() * 100,\n                    SPD4: Math.random() * 100\n                });\n            }, 1000);\n        },\n        methods: {\n            initChart() {\n                const ctx = this.$refs.chartCanvas;\n                this.chart = new Chart(ctx, {\n                    type: 'line',\n                    data: {\n                        labels: [],  // Initialize with empty labels\n                        datasets: [\n                            { label: 'SPD1', data: [], borderColor: 'red', borderWidth: 2 },\n                            { label: 'SPD2', data: [], borderColor: 'blue', borderWidth: 2 },\n                            { label: 'SPD3', data: [], borderColor: 'green', borderWidth: 2 },\n                            { label: 'SPD4', data: [], borderColor: 'purple', borderWidth: 2 }\n                        ]\n                    },\n                    options: {\n                        responsive: true,\n                        scales: {\n                            x: { type: 'time', time: { unit: 'second' } },\n                            y: { beginAtZero: true, title: { display: true, text: 'Speed (MPH)' } }\n                        }\n                    }\n                });\n            },\n            updateChart(payload) {\n                const timeLabel = new Date(payload.date).toLocaleTimeString();\n                this.chart.data.labels.push(timeLabel);\n                this.chart.data.datasets[0].data.push(payload.SPD1);\n                this.chart.data.datasets[1].data.push(payload.SPD2);\n                this.chart.data.datasets[2].data.push(payload.SPD3);\n                this.chart.data.datasets[3].data.push(payload.SPD4);\n\n                // Keep only the last 20 data points for clarity\n                if (this.chart.data.labels.length > 20) {\n                    this.chart.data.labels.shift();\n                    this.chart.data.datasets.forEach(dataset => dataset.data.shift());\n                }\n                this.chart.update();\n            }\n        }\n    };\n</script>\n\n<style>\n.chart-container {\n    width: 100%;\n    height: 100%;\n}\n</style>\n",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 580,
        "y": 180,
        "wires": [
            [
                "0b1f9eab6a56695a"
            ]
        ]
    },
    {
        "id": "0b1f9eab6a56695a",
        "type": "debug",
        "z": "5df899d3ab0f31cc",
        "name": "debug 3",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 820,
        "y": 180,
        "wires": []
    },
    {
        "id": "2c34b9c7d6324531",
        "type": "ui-group",
        "name": "Devices",
        "page": "7294756f31e17b81",
        "width": "6",
        "height": "1",
        "order": 2,
        "showTitle": true,
        "className": "",
        "visible": "true",
        "disabled": "false",
        "groupType": "default"
    },
    {
        "id": "7294756f31e17b81",
        "type": "ui-page",
        "name": "Home",
        "ui": "59dc26b2539761ad",
        "path": "/home",
        "icon": "home",
        "layout": "grid",
        "theme": "52ba8a01d6eda628",
        "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": 5,
        "className": "",
        "visible": true,
        "disabled": false
    },
    {
        "id": "59dc26b2539761ad",
        "type": "ui-base",
        "name": "UI Name",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-control",
            "ui-chart",
            "ui-gauge"
        ],
        "showPathInSidebar": false,
        "showPageTitle": true,
        "navigationStyle": "default",
        "titleBarStyle": "default"
    },
    {
        "id": "52ba8a01d6eda628",
        "type": "ui-theme",
        "name": "Mobile",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094ce",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "compact",
            "pagePadding": "5px",
            "groupGap": "5px",
            "groupBorderRadius": "10px",
            "widgetGap": "5px"
        }
    }
]

Yeah. Many things.

When mounted, it doesn't mean that the script is loaded. If the Chart object in window is not yet available, you cant init it. Look at the examples and follow the practice.

The labels is basically an array of the names of datasets.
If you consistently need to have 4 datasets, it can be hardcoded. (if you do build dedicated chart)

If you have labels in dataset (chart.data.dataset[index].label) you don't need to define labels separately.

Watching the chart.data.labels count has nothing related to the dataset.data so that cant work anyhow.

Examine the examples and read the chart.js documentation online.

Got it working - thank you!!!!

1 Like