# Questions to 'charts' in UIBUILDER

**URL:** https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562
**Category:** General
**Tags:** uibuilder
**Created:** [8 June 2024 15:05 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562 "2024-06-08T15:05:36Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![GretaC](https://avatars.discourse-cdn.com/v4/letter/g/bb73d2/32.png) [@GretaC](https://discourse.nodered.org/u/GretaC)
#### Post date: [8 June 2024 15:05 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/1 "2024-06-08T15:05:36Z")

</div>

My goal was to move from a NR -Desktop chart to an uibuilder chart.  
Due to my limited experience in js an nearly no experience in html I was not aware that 'canvas' is one key for my solution.

So I asked AI for a proposal and got the main information. So I succeded, after a week of testing, investigating, frustrating, debugging, ...

You can see the result in the picture and the code for it below.

![Bildschirmfoto vom 2024-06-08 16-32-04](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/9/699cac9135d92b71b644019cd56d430a66f540b0.png)

```auto
[
    {
        "id": "6eb908405022da43",
        "type": "inject",
        "z": "c441b77c555275d8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "2",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 250,
        "y": 380,
        "wires": [
            [
                "f66abe8c758b6825"
            ]
        ]
    },
    {
        "id": "f66abe8c758b6825",
        "type": "function",
        "z": "c441b77c555275d8",
        "name": "Update with random numbers",
        "func": "msg.payload = [Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100];\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 470,
        "y": 380,
        "wires": [
            [
                "49ffaa2ec54f8a2f"
            ]
        ]
    },
    {
        "id": "49ffaa2ec54f8a2f",
        "type": "uibuilder",
        "z": "c441b77c555275d8",
        "name": "",
        "topic": "",
        "url": "ui-test-9",
        "okToGo": true,
        "fwdInMessages": false,
        "allowScripts": false,
        "allowStyles": false,
        "copyIndex": true,
        "templateFolder": "blank",
        "extTemplate": "",
        "showfolder": false,
        "reload": false,
        "sourceFolder": "src",
        "deployedVersion": "6.8.2",
        "showMsgUib": false,
        "title": "",
        "descr": "",
        "x": 690,
        "y": 380,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "f3cd0e3ff17a3815",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.html",
        "info": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"UTF-8\">\n <title>My Chart</title>\n\n <!-- next line missing in AI -->\n <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n\n <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n <link rel=\"stylesheet\" href=\"index.css\">\n <script src=\"index.js\" ></script>\n</head>\n\n<body>\n <h1>Chart Example</h1>\n <canvas id=\"myChart\" width=\"400\" height=\"200\"></canvas>\n <!-- 'defer' missing in next line from AI -->\n <script defer src=\"index.js\"></script>\n</body>\n\n</html>",
        "x": 560,
        "y": 280,
        "wires": []
    },
    {
        "id": "0e67de5647fea05c",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.js",
        "info": "document.addEventListener('DOMContentLoaded', (event) => {\n // Data for the chart\n const data = {\n labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],\n datasets: [{\n label: 'My First dataset',\n backgroundColor: 'rgba(255, 99, 132, 0.2)',\n borderColor: 'rgba(255, 99, 132, 1)',\n borderWidth: 1,\n data: [65, 59, 80, 81, 56, 55, 40],\n }]\n };\n\n // Configuration for the chart\n const config = {\n type: 'bar',\n data: data,\n options: {\n scales: {\n y: {\n beginAtZero: true\n }\n }\n }\n };\n\n // Render the chart\n myChart = new Chart(\n document.getElementById('myChart'),\n config\n );\n});\n\n// Listen for messages from Node-RED\nuibuilder.onChange('msg', function (msg) {\n // Update chart data on receiving new messages\n myChart.data.datasets[0].data = msg.payload;\n myChart.update();\n});",
        "x": 670,
        "y": 300,
        "wires": []
    },
    {
        "id": "a1bce227565e2317",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.css",
        "info": "body {\n font-family: Arial, sans-serif;\n margin: 20px;\n}\n\nh1 {\n text-align: center;\n}\n\ncanvas {\n display: block;\n margin: 0 auto;\n}",
        "x": 780,
        "y": 320,
        "wires": []
    }
]

```

Now I want gain a better understanding. During the investigation I got some question marks in my mind, perhaps you can help me:

Question 1:  
If I edit 'index.js' I see that several names are 'undefined'. Coming from Pascal and C I would say they are not 'declared'. At least they are not declared in 'index.js'. (see picture)

![Bildschirmfoto vom 2024-06-08 11-23-53](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/1/217d0b47586208b33aa35e9b9c4c2a84169e9667.png)

But it seems to be some kind of 'zombies' 😉, because the code is running.

Can anybody tell me how this works?

Question 2:  
In AI's proposal 'defer' is missing in '\<script defer src="index.js"\>\</script\>'.  
My understanding is, that 'defer' affects the first time execution of scripts, if it is executed during parsing, or not.  
My observation in the debugger is, that 'uibuilder.onChange' is not available if 'defer' is not set. 'Not available' means: I cannot set a break point here. And as a matter of course this part is not executed if the 'injcect' fires.  
IF 'defer' is set, everything works fine.

Can anybody tell me?

Question 3:  
When inspecting 'myChart' there is no 'data' field in it. My data are in 'myChart.config.\_config.data.datasets[0].data'.  
But the update method 'uibuilder.onChange(...)' has 'myChart.data.datasets[0].data = msg.payload;'.

 ![Bildschirmfoto vom 2024-06-08 16-24-20](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/b/6/b69135d588308b8136c8aeddb29d2ba4a16e8221.png)  
(the screen shot shows the important part of the object 'myChart'.)

Can anybody tell me the mechanism?

Sorry. I know. It's a lot...

---

<div class="post-metadata">

### Author: ![fmarzocca](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/fmarzocca/32/35901_2.png) [@fmarzocca](https://discourse.nodered.org/u/fmarzocca)
#### Post date: [8 June 2024 15:41 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/2 "2024-06-08T15:41:37Z")

</div>

I had a great experience by using [Google Charts](https://developers.google.com/chart/interactive/docs/gallery/columnchart?hl=en) with uibuilder...

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [8 June 2024 15:55 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/3 "2024-06-08T15:55:50Z")

</div>

> [@GretaC](#):
>
> My goal was to move from a NR -Desktop chart to an uibuilder chart.

Congratulations for making the smart move. 😁

> [@GretaC](#):
>
> 'canvas'

Canvas is one method for adding graphics to a web page, svg is the other main way (other than images).

> **[When to Use SVG vs. When to Use Canvas | CSS-Tricks](https://css-tricks.com/when-to-use-svg-vs-when-to-use-canvas/)**
>
> SVG and canvas are both technologies that can draw stuff in web browsers, so they are worth comparing and understanding when one is more suitable than the

Either approach is applicable for showing charts on a page and different charting libraries will use different approaches.

> [@GretaC](#):
>
> perhaps you can help me

I will certainly try.

> [@GretaC](#):
>
> If I edit 'index.js' I see that several names are 'undefined'. Coming from Pascal and C I would say they are not 'declared'. At least they are not declared in 'index.js'. (see picture)
> 
> But it seems to be some kind of 'zombies' 😉, because the code is running.
> 
> Can anybody tell me how this works?

Yes, certainly. It is "only" the editor that is telling you that it doesn't know about them, this is a false positive. It happens simply because the Monaco editor, in this case, has no way of knowing that those global variables are defined elsewhere. There are ways that you could try to let the editor know that they exist though in practice, this can take some effort and, in this case anyway, is probably not worth it.

Do remember here that the code you are editing is on the server whereas it RUNs in the browser. So it isn't that surprising that there is an "understanding" gap between the editor and the code.

The links to the JavaScript libraries you have in your HTML not only load the library code into browser memory but those libraries then normally self-execute to make their use easy. In doing so, they create the global variables you are seeing. This "magic" is far from obvious at first sight and is rarely explicitly documented.

> [@GretaC](#):
>
> In AI's proposal 'defer' is missing in ''.  
> My understanding is, that 'defer' affects the first time execution of scripts, if it is executed during parsing, or not.  
> My observation in the debugger is, that 'uibuilder.onChange' is not available if 'defer' is not set. 'Not available' means: I cannot set a break point here. And as a matter of course this part is not executed if the 'injcect' fires.  
> IF 'defer' is set, everything works fine.
> 
> Can anybody tell me?

If you were to examine much of the example browser javascript code on the Internet, you will find many people recommending that you put the javascript at the end of the `<body>` section of you html. In days past, this was a lot more efficient because `<link>`d javascript in the head section delayed the loading and rendering of the visible HTML, it wasn't very perfomant at all.

Which is why JavaScript was updated to allow the `defer` keyword which does exactly what it says. It makes it very similar to putting the links at the end of the body. However, it has the added benefit of keeping the javascript links separate from the visible HTML layout. I find this approach much better and cleaner and so in a previous update to UIBUILDER, I changed the default templates to use this newer style.

Unfortunately, the LLM's that ChatGPT et-al use are not actually "intelligent" in any creative sense. They rely on existing writing and code done by people in the past. So they tend to not use the `defer` keyword. This and existing examples perpetuate a now myth about the best way to load JavaScript.

If you don't want to use`defer`, you should move all of the javascript links down to the end of your HTML.

> [@GretaC](#):
>
> My observation in the debugger is, that 'uibuilder.onChange' is not available if 'defer' is not set.

I'm not quite sure why that is actually, everything should still work without the `defer` keyword - just not efficienly.

> [@GretaC](#):
>
> Can anybody tell me the mechanism?

Hard to do without knowing which charting library you are using.

In general, it is worth knowing that JavaScript is a bit of a strange language at times. The `myChart` object might possibly have things in it that are not visible to the `console.log` debug output that I assume you've used.

Perhaps try `console.log(myChart.data)`? It does strike me that `myChart.data` might be some kind of defined shortcut to make it easier to use.

Let me know what chart library you are using though if you want me to check it out.

> [@GretaC](#):
>
> Sorry. I know. It's a lot...

Not at all, JavaScript is not the easiest language to get your head around (past the basics anyway) - especially if you have come from more formal languages.

PS: You could always ask your favourite LLM tool to describe the differences between links with and without the defer attribute. It would, in fact, be interesting to hear what they say.

---

<div class="post-metadata">

### Author: ![GretaC](https://avatars.discourse-cdn.com/v4/letter/g/bb73d2/32.png) [@GretaC](https://discourse.nodered.org/u/GretaC)
#### Post date: [9 June 2024 15:52 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/4 "2024-06-09T15:52:26Z")

</div>

@TotallyInformation Thank's a lot for spending your time to read my post and answering my questions. It's really helpful!

> [@TotallyInformation](#):
>
> Do remember here that the code you are editing is on the server whereas it RUNs in the browser. So it isn't that surprising that there is an "understanding" gap between the editor and the code.

That's really a good point. I totally missed it. Mostly I work completely local or edit local and debug on a remote system.  
I checked this in the browsers debugger (firefox: F12) and here is everything fine.

I invested some more time to understand the data issue and found, that both works:  
`myChart.data.datasets[0].data = msg.payload;`  
as well as  
`myChart.config._config.data.datasets[0].data= msg.payload;`.  
So it is as it is and if I follow the doc of canvas in the future, I'm hopefully on the save side.

The 'defer' issue is still not fully understood, here I have to spend some more time. But the important thing is that it works, if it is set........

I do not use any special library. I even just did quick check and installed a new nodered instance (proxmox/lxc) and installed in nr nothing but 'node-red-contrib-uibuilder' and my code from above. 'defer' at any position (head/top, head/bottom, body): if present the 'uibuilder'- block is present, if not present, the block is not.

Btw: Now I know that this 'defer' issue is the main reason for my confusion. I was forced to debug problems started 😀 But I learned a lot.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [9 June 2024 22:11 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/5 "2024-06-09T22:11:34Z")

</div>

> [@GretaC](#):
>
> The 'defer' issue is still not fully understood, here I have to spend some more time

A couple of links to help:

- [Scripts: async, defer](https://javascript.info/script-async-defer)
- [JavaScript Performance – How to Improve Page Speed with async and defer](https://www.freecodecamp.org/news/javascript-performance-async-defer/)
- [Understanding Async/Defer in JavaScript: Enhancing Performance and Responsiveness | by Ömür Bilgili | Medium](https://omurbilgili.medium.com/understanding-async-defer-in-javascript-enhancing-performance-and-responsiveness-237b56da37dd)

---

<div class="post-metadata">

### Author: ![GretaC](https://avatars.discourse-cdn.com/v4/letter/g/bb73d2/32.png) [@GretaC](https://discourse.nodered.org/u/GretaC)
#### Post date: [12 June 2024 07:47 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/6 "2024-06-12T07:47:14Z")

</div>

Perhaps the following code makes my 'question mark' it a little visible to you. It is the above example. I just added a button in the html and the related function in js.

```auto
[
    {
        "id": "6eb908405022da43",
        "type": "inject",
        "z": "c441b77c555275d8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 240,
        "y": 380,
        "wires": [
            [
                "f66abe8c758b6825"
            ]
        ]
    },
    {
        "id": "f66abe8c758b6825",
        "type": "function",
        "z": "c441b77c555275d8",
        "name": "Update with random numbers",
        "func": "msg.payload = [Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100, Math.random() * 100];\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 470,
        "y": 380,
        "wires": [
            [
                "49ffaa2ec54f8a2f"
            ]
        ]
    },
    {
        "id": "49ffaa2ec54f8a2f",
        "type": "uibuilder",
        "z": "c441b77c555275d8",
        "name": "",
        "topic": "",
        "url": "ui-test-9",
        "okToGo": true,
        "fwdInMessages": false,
        "allowScripts": false,
        "allowStyles": false,
        "copyIndex": true,
        "templateFolder": "blank",
        "extTemplate": "",
        "showfolder": false,
        "reload": false,
        "sourceFolder": "src",
        "deployedVersion": "6.8.2",
        "showMsgUib": false,
        "title": "",
        "descr": "",
        "x": 690,
        "y": 380,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "f3cd0e3ff17a3815",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.html",
        "info": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <title>GCh - Chart</title>\n <meta charset=\"UTF-8\">\n\n <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script> \n \n <link rel=\"stylesheet\" href=\"index.css\">\n \n</head>\n\n<body>\n <h1>Chart Example</h1>\n <canvas id=\"myChart\" width=\"400\" height=\"200\"></canvas>\n\n <script defer src=\"index.js\"></script>\n\n <button type=\"button\" onclick=\"newValues()\"> Werte ändern </button>\n\n</body>\n\n</html>",
        "x": 560,
        "y": 280,
        "wires": []
    },
    {
        "id": "0e67de5647fea05c",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.js",
        "info": "document.addEventListener('DOMContentLoaded', (event) => {\n // Data for the chart\n const data = {\n labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],\n datasets: [{\n label: 'My First dataset',\n backgroundColor: 'rgba(255, 99, 132, 0.2)',\n borderColor: 'rgba(255, 99, 132, 1)',\n borderWidth: 1,\n data: [65, 59, 80, 81, 56, 55, 40],\n }]\n };\n\n // Configuration for the chart\n const config = {\n type: 'bar',\n data: data,\n options: {\n scales: {\n y: {\n beginAtZero: true\n }\n }\n }\n };\n\n // Render the chart\n myChart = new Chart(\n document.getElementById('myChart'),\n config\n );\n});\n\n// Listen for messages from Node-RED\nuibuilder.onChange('msg', function (msg) {\n myChart.data.datasets[0].data = msg.payload;\n myChart.update();\n\n// dummy code just to give a target for a breakpoint\n var t = 10;\n if (t==10)\n t = 0;\n});\n\nfunction newValues() {\n myChart.data.datasets[0].data = [50, 60, 70, 80, 90, 100, 110];\n myChart.update();\n}\n",
        "x": 670,
        "y": 300,
        "wires": []
    },
    {
        "id": "a1bce227565e2317",
        "type": "comment",
        "z": "c441b77c555275d8",
        "name": "index.css",
        "info": "body {\n font-family: Arial, sans-serif;\n margin: 20px;\n}\n\nh1 {\n text-align: center;\n}\n\ncanvas {\n display: block;\n margin: 0 auto;\n}",
        "x": 780,
        "y": 320,
        "wires": []
    }
]

```

This function obviously has no access to NR. I understand that this is the main feature of UIBUILDER.  
But the function is available if 'defer' is set or not, whereas it is not the case for 'uibuilder.onChange(...)'

At the end it is not important, I just use 'defer'. But perhaps it's an issue in 'uibuilder'. (?)

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [12 June 2024 15:04 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/7 "2024-06-12T15:04:19Z")

</div>

OK, lets start by tidying up your HTML:

```auto
<!doctype html>
<html lang="en"><head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="../uibuilder/images/node-blue.ico">

    <title>GCh - Chart - Node-RED uibuilder</title>
    <meta name="description" content="Node-RED uibuilder - GCh - Chart">

    <!-- Your own CSS (defaults to loading uibuilders css)-->
    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->
    <script defer src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script defer src="../uibuilder/uibuilder.iife.min.js"></script>
    <script defer src="./index.js"></script>
    <!-- #endregion -->

</head><body class="uib">
    
    <h1 class="with-subtitle">GCh - Chart</h1>
    <div role="doc-subtitle">Using the UIBUILDER IIFE library.</div>

    <div id="more"></div>

    <canvas id="myChart" width="400" height="200"></canvas>

    <button type="button" onclick="newValues()"> Werte ändern </button>

</body></html>

```

You either use defer in the head OR you put the js load (without defer) at the end of the body. The defer keyword effectively does the same thing as putting the link at the end of the body, it is just neater and more in line with modern standards.

If you put the link in the head without defer but still leave defer on the load of the uibuilder library, things will happen out of order - your index.js would load before the uibuilder library and so you could not use the `uibuilder` global at all.

Similarly, leaving the uibuilder library in the head with the defer on it and loading the others in the body will result in the uibuilder library loading last and therefore out of order.

Libraries, as it states in the comments for the default template, MUST be loaded in the right order or things won't work. The `defer` keyword changes the order when used in the `<head>` HTML section and does nothing in the `<body>`.

> [@GretaC](#):
>
> But perhaps it's an issue in 'uibuilder'. (?)

Nope 😀

It is simply the way that the browser loads things.

By the way:

> [@GretaC](#):
>
> I do not use any special library.

Yes, you do, you are using the [ChartJS](https://www.npmjs.com/package/chart.js) library.

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [10 September 2024 15:05 UTC](https://discourse.nodered.org/t/questions-to-charts-in-uibuilder/88562/8 "2024-09-10T15:05:03Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
