# Uibuilder vega chart and db-s integration

**URL:** <https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611>\
**Category:** General\
**Tags:** uibuilder\
**Created:** [23 December 2021 12:53 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611 "2021-12-23T12:53:29Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [23 December 2021 12:53 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/1 "2021-12-23T12:53:29Z")

</div>

Hi,

I've started to experiment with uibuilder and Vue, and I'm having problems integrating Vega charts to the uibuilder.

Here are the files (modified from Julian's charting examples):  
[flows (84).json](https://discourse.nodered.org/uploads/short-url/ncF6BXuc0liyEyqEY8e3eEFhbTD.json) (16.0 KB)

Unfortunately, I can't make heads or tales with this vega charts integration - can anyone help me out?  
I've also placed the standard dashboard vega flow - which I am trying to integrate into uibuilder.

To be honest, I don't undestand how the other charts (from Julian's example) were run. Couldn't find any function which runs them (besides onload which is obviously used for dynamic input).

1. I have placed the data property into the vega spec itself just to test out the vega first - but I dont know where to put the spec variable.
2. Also, I'm not sure how to start vegaEmbed function from HTML file using script tags - nothing is the same as the dashboard.

Unfortunately I'm am not a dev by profession, so this is my way to adjust to the new programming enviroment.  
I've seen the basics of Vue on thenetninjas channel on yt, but I don't know how to use it practically with charts and databases...

Also, does anyone have some examples how to use databases (sqlite with uibuilder and vue)?  
I dont know if one should write everything in Vue CLI or use node-red as before only with minor help of a single uibuilder node?

---

<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:** [23 December 2021 13:02 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/2 "2021-12-23T13:02:42Z")

</div>

Hi, helps if you share your front-end code rather than just the flow. A picture of the flow can help as well as most of us don't really want to keep loading random flows.

The reason you don't see something explicit starting the charts is that they are configured to auto-run when loaded via a script link. Most front-end libraries do, including the uibuilder front-end. Though you have to run the start function (for reasons explained in the docs), the `uibuilder` object is auto-created for you. Same with VueJS, etc.

Remember that uibuilder doesn't _require_ you to use a front-end library. So the best place to start is to start with the blank template, cut the html file down to a minimum and then add a vega example from their website.

Then you can work out what format of data it needs and then you can send that from Node-RED via the uibuilder node.

Once you have the basics working, you can add VueJS or something else if you want the reactivity.

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [23 December 2021 13:55 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/3 "2021-12-23T13:55:17Z")

</div>

Ok I'll try without Vue and get back to you.  
Anyway, here are the files:

html:

```auto
<!doctype html><html lang="en"><head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

    <title>Vega charts Example - Node-RED UI Builder</title>
    <meta name="description" content="Node-RED UI Builder - Vega chart Example">

    <link rel="icon" href="./images/node-blue.ico">

    <link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap/dist/css/bootstrap.min.css" />
    <link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css" />

    <link rel="stylesheet" href="./index.css" media="all">
</head><body>
    <div id="app">
        <b-container id="app_container">

            <h1>
                Example of using Vega charts with uibuilder, VueJS and bootstrap-vue
            </h1>

            <b-row>
                <div id="vis1" style="height:500px"></div>
                <script>

                    vegaEmbed("#vis1", spec, {"actions": false}).then(result => console.log(result)).catch(console.warn);

                </script>
                </div>
            <!-- 
                <b-card cols="5" class="mr-1" header="Bar Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                    <column-chart :data="[['Sun', 32], ['Mon', 46], ['Tue', 28]]"></column-chart>
                </b-card>

                <b-card class="mr-1" header="Line Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                    <line-chart :data="lineChartData"></line-chart>
                </b-card>

                <b-card class="mr-1" header="Multi-Series Line Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                    <line-chart :data="lineChartData2"></line-chart>
                </b-card>

                <b-card class="w-100 mt-3 mb-3" header="Area Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                    <area-chart :data="areaChartData"></area-chart>
                </b-card>

                <b-card class="mr-1" header="Geo Chart (Google)" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                    <geo-chart width="800px" :data="[['United States', 44], ['Germany', 23], ['Brazil', 22]]"></geo-chart>
                </b-card>

                <b-card class="mr-1" header="Timeline (Google)" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                   <timeline width="800px" :data="[['Washington', '1789-04-29', '1797-03-03'], ['Adams', '1797-03-03', '1801-03-03']]"></timeline>
                </b-card>
            -->
            </b-row>

        </b-container>
    </div>

    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script src="../uibuilder/vendor/vue/dist/vue.min.js"></script>
    <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script>

    <!-- Loading from CDN, use uibuilder to install packages and change to vendor links -->
    <!-- <script src="https://unpkg.com/chart.js@2.8.0/dist/Chart.bundle.js"></script> Chart.js -->
    <!-- <script src="https://www.gstatic.com/charts/loader.js"></script> Google Charts -->
    <!-- <script src="https://code.highcharts.com/highcharts.js"></script> HighCharts -->
    <!-- <script src="https://unpkg.com/vue-chartkick@0.5.1"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
	<script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>

    <script src="./uibuilderfe.min.js"></script> <!-- //prod version -->
    <script src="./index.js"></script>

</body></html>

```

js:

```auto
/* jshint browser: true, esversion: 5 */

/* globals document,Vue,window,uibuilder */

// @ts-nocheck

/*

  Copyright (c) 2019 Julian Knight (Totally Information)

  Licensed under the Apache License, Version 2.0 (the "License");

  you may not use this file except in compliance with the License.

  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software

  distributed under the License is distributed on an "AS IS" BASIS,

  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  See the License for the specific language governing permissions and

  limitations under the License.

*/

'use strict'

/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */

// eslint-disable-next-line no-unused-vars

var app1 = new Vue({

    el: '#app',

    spec :

    {

        "description": "A basic bar chart example, with value labels shown upon mouse hover.",

        "width": 400,

        "height": 200,

        "padding": 5,

     

        "data": [

          {

            "name": "table",

            "values": [

              {"category": "A", "amount": 28},

              {"category": "B", "amount": 55},

              {"category": "C", "amount": 43},

              {"category": "D", "amount": 91},

              {"category": "E", "amount": 81},

              {"category": "F", "amount": 53},

              {"category": "G", "amount": 19},

              {"category": "H", "amount": 87}

            ]

          }

        ],

     

        "signals": [

          {

            "name": "tooltip",

            "value": {},

            "on": [

              {"events": "rect:mouseover", "update": "datum"},

              {"events": "rect:mouseout", "update": "{}"}

            ]

          }

        ],

     

        "scales": [

          {

            "name": "xscale",

            "type": "band",

            "domain": {"data": "table", "field": "category"},

            "range": "width",

            "padding": 0.05,

            "round": true

          },

          {

            "name": "yscale",

            "domain": {"data": "table", "field": "amount"},

            "nice": true,

            "range": "height"

          }

        ],

     

        "axes": [

          { "orient": "bottom", "scale": "xscale" },

          { "orient": "left", "scale": "yscale" }

        ],

     

        "marks": [

          {

            "type": "rect",

            "from": {"data":"table"},

            "encode": {

              "enter": {

                "x": {"scale": "xscale", "field": "category"},

                "width": {"scale": "xscale", "band": 1},

                "y": {"scale": "yscale", "field": "amount"},

                "y2": {"scale": "yscale", "value": 0}

              },

              "update": {

                "fill": {"value": "steelblue"}

              },

              "hover": {

                "fill": {"value": "red"}

              }

            }

          },

          {

            "type": "text",

            "encode": {

              "enter": {

                "align": {"value": "center"},

                "baseline": {"value": "bottom"},

                "fill": {"value": "#333"}

              },

              "update": {

                "x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},

                "y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},

                "text": {"signal": "tooltip.amount"},

                "fillOpacity": [

                  {"test": "datum === tooltip", "value": 0},

                  {"value": 1}

                ]

              }

            }

          }

        ]

      },

     

    data: {

        // Single series line chart

        lineChartData: [

            ['Jan', 4], ['Feb', 2], ['Mar', 10], ['Apr', 5], ['May', 3],

        ],

        // Multi-series line chart

        lineChartData2: [

            {name: 'Workout', data: {'2017-01-01 00:00:00 -0800': 3, '2017-01-02 00:00:00 -0800': 4}},

            {name: 'Call parents', data: {'2017-01-01 00:00:00 -0800': 5, '2017-01-02 00:00:00 -0800': 3}},

        ],

        // Area chart

        areaChartData: [], //{

            //'2017-01-01 00:00:00 -0800': 2,

            //'2017-01-01 00:01:00 -0800': 5,

        //},

       

    }, // --- End of data --- //

    computed: {

    }, // --- End of computed --- //

    methods: {

    }, // --- End of methods --- //

    // Available hooks: init,mounted,updated,destroyed

    mounted: function(){

        / **** REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3

         * Pass the namespace and ioPath variables if hosting page is not in the instance root folder

         * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.

         * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names

         */

        uibuilder.start()

        var vueApp = this

        // Process new messages from Node-RED

        uibuilder.onChange('msg', function (newVal) {

            // We are assuming that msg.payload is an array like [datenum, value]

            // Add new element

            vueApp.areaChartData.push( new Array( (new Date(newVal.payload[0])), newVal.payload[1] ) )

            // If data array > 1000 points, keep it at that length by losing the first point

            if ( vueApp.areaChartData.length > 10 ) vueApp.areaChartData.shift()

            //console.log(vueApp.areaChartData)

        })

    } // --- End of mounted hook --- //

}) // --- End of app1 --- //

// EOF

```

flow picture:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/f/9fe309ab07556679a51f8536f9458f536595083b.png)

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [29 December 2021 09:32 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/4 "2021-12-29T09:32:20Z")

</div>

> [@TotallyInformation](#):
>
> Remember that uibuilder doesn't _require_ you to use a front-end library. So the best place to start is to start with the blank template, cut the html file down to a minimum and then add a vega example from their website.  
> ..
> 
> Once you have the basics working, you can add VueJS or something else if you want the reactivity.

OK, finally I'm back to this project and I was able to load the charts only with basic html and JS which had vega object and loader.

Next: dynamic input and then DB - so perhaps I will need more help,

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [29 December 2021 17:01 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/5 "2021-12-29T17:01:08Z")

</div>

OK, now I have ALOT more questions. Seems like I'm at the start of the uibuilder+Vue.JS learning curve.  
From my perpective, transition from the dashboard to uibuilder with a front-end framework is tough.

Let me explain what I'm trying to achieve:  
A "simple" flow which uses a button which when pressed loads new random data into vega charts and exports the chart data out of the uibuilder node to the db every 5 mins. Is this the way to go?  
I try to pursue the Vue approach because all the charting examples are made with Vue, and because this is my ultimate goal. (I've added some 8 example flows but I still don't understand)

What I have made so far:  
I have managed to get the static chart to show by avoiding the Vue.JS, and putting the spec object and the vegaEmbed in the index.js file (only this is in it, nothing else). html file contains this line `<div id="vis1" style="height:500px"></div>` which is the container where the charts are shown.

Now for the questions:

1. I've been following the Vue tutorial for beginners and don't undestand why do the use

```auto
const app = Vue.createApp({
  data() {
...
  }
})

app.mount('#app')

```

and all the examples for the uibuilder use:

```auto
const app = new Vue({
    el: '#app',

    data() {

```

whats the difference?

1. Do I need to use this kind of tags to call the charts? `<apexchart width="100%" type="donut" :options="doptions" :series="dseries"></apexchart>`  
I noticed this libraries have a component for Vue ready and the correct way to use it by calling it in the JS file like this?

```auto
/** Reference the apexchart component (removes need for a build step) */
Vue.component('apexchart', VueApexCharts)

```

How is this applicable to the vega charts? Which one do I need to look for, Vega or VegaEmbed?  
some links:

> **[Render Vega and Vega-Lite source in a Vue.js app](https://www.fabiofranchino.com/blog/render-vega-and-vega-lite-source-in-vue-js/)**
>
> Senior Designer / Technologist

> **[GitHub - nesterone/vue-vega: Vega Lite and Vega bridge to Vue.js ecosystem](https://github.com/nesterone/vue-vega)**
>
> Vega Lite and Vega bridge to Vue.js ecosystem. Contribute to nesterone/vue-vega development by creating an account on GitHub.

I'm not sure these are 100% functional, as I don't use the classic 'premade' charts but instead a multi axis multi type timeline charts...

1. And while we're at the apexchart example, how to get familiar with this?  
JS:

```auto
        // Data for donut chart
        doptions: {},
        dseries: [44, 55, 41, 17, 15]
...
        uibuilder.onChange('msg', function (newVal) {
            if ( typeof newVal.payload === 'number' ){
                // Add new element
                vueApp.dseries.push(newVal.payload)
                // Lose the first element
                vueApp.dseries.shift()
                //console.log(vueApp.dseries)
            }
        })

```

How does this work? I don't understand..........

---

<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:** [29 December 2021 21:39 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/6 "2021-12-29T21:39:55Z")

</div>

> [@nerevar](#):
>
> transition from the dashboard to uibuilder with a front-end framework is tough

It can be if you aren't familiar with web development, there are a lot of things to learn.

The main thing to remember is that uibuilder iteself is very simple to use. But it's main purpose is to act as a link between the data you throw about in Node-RED and a users browser (where the UI lives). If you can keep that straight, it will really help you as you progress.

> [@nerevar](#):
>
> A "simple" flow which uses a button which when pressed loads new random data into vega charts and exports the chart data out of the uibuilder node to the db every 5 mins. Is this the way to go?

So lets break this down. There are three things you are trying to achieve.

1. Get some data
2. Show that data in a chart.
3. Save that data to a DB for later use every 5 minutes.

Actually, only step 2 might use uibuilder 🙂

There isn't any point in trying to save the data "from the chart". Because Node-RED can already help you with that and it already has the data. The only reason to get uibuilder involved with step 3 would be if you wanted the USER of the chart to select what data to save. If you just want it saving every 5 minutes, get Node-RED to do that, it is what it is good at and will be a lot simpler than trying to send it to the browser and then send it back (which is where uibuilder is really doing the work).

Now, of course, step 2 is a little more complex than you initially state because actually you want the chart to update whenever new data comes along. But the Vega library may be able to do this without VueJS (we'll come back to VueJS in a moment, bear with me). This example shows you a simple web page that updates a chart from data sent over a websocket connection. [Vega-Lite with Websockets - bl.ocks.org](https://bl.ocks.org/domoritz/8e1e4da185e1a32c7e54934732a8d3d5)  
If you look at the script embedded in the html file, you can see where it creates a websocket and listens for data over it. This is what uibuilder sets up for you. Instead of `conn.onmessage = function(event) {`, you would have `uibuilder.onChange('msg', function(msg){` and instead of `event.data`, you would simply use `msg`. The part about cennting to the echo server and the `conn.onopen` isn't needed at all since uibuilder takes care of all the details for you.

I use that as an example that I hope shows that VueJS is not really needed for simple things. However, it becomes really helpful as the complexity of your web app grows.

> [@nerevar](#):
>
> I've been following the Vue tutorial for beginners and don't undestand why do the use

First thing to check is that you understand there are differences between Vue v2 and v3? Stick with v2 for now as not everything is yet compatible with v3. If you are following a tutorial, it should tell you which version it is targetting.

Next, here is a QA about this topic: [vue.js - Difference between .$mount() and el [Vue JS] - Stack Overflow](https://stackoverflow.com/questions/46831452/difference-between-mount-and-el-vue-js)

The answer to your question is: not a lot! All it means is that you get to choose when you create the Vue app. In by far the majority of cases, you want the app created as early as possible and so the `const app = new Vue({...})` version is going to be the simplest anyway.

> [@nerevar](#):
>
> Do I need to use this kind of tags to call the charts?

OMG!!! I've just managed to find some time to try and use Vega for the first time - it is HORRIBLE!!

Just a quick check ApexChart is obviously not the same as Vega - so your examples don't quite align. ApexChart is much easier to use but probably not as powerful.

The component is likely to be better for you if you are going to be creating something more complex that will benefit from a build step (using webpack, parcel or similar). Annoyingly, all the examples for vue-vega assume that you will be using a build step to "compile" the code. Example: [Vue - CodeSandbox](https://codesandbox.io/s/1plts) I've not managed to find any that let you load things directly.

> [@nerevar](#):
>
> And while we're at the apexchart example, how to get familiar with this?

As mentioned, apexchart isn't the same as Vega.

All that example is doing is pushing new data onto the end of the series that apexchart is showing. But, at the same time, it is dropping off the first element of the array after the new element is added so that you don't end up with an infinite number of elements in the array which would eventually crash the browser tab. `push` and `shift` are JavaScript array functions.

* * *

Right, so a quick and nasty Vega example - without VueJS for now:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/5/c/5cd265076a9d6ef5793374f79c172c7959e0fbc6.png)

```auto
[{"id":"06557b5a92be6c25","type":"inject","z":"b533fe741719fa7a","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{ \"a\": \"j\", \"b\": 70 }","payloadType":"json","x":240,"y":220,"wires":[["e0e67a1f4275c9a0"]]},{"id":"e0e67a1f4275c9a0","type":"uibuilder","z":"b533fe741719fa7a","name":"","topic":"","url":"vega","fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"useSecurity":false,"allowUnauth":false,"allowAuthAnon":false,"sessionLength":432000,"tokenAutoExtend":false,"reload":true,"sourceFolder":"src","deployedVersion":"5.0.0-dev","x":430,"y":220,"wires":[[],[]]}]

```

index.html

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

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Node-RED UI Builder - Blank template</title>
    <meta name="description" content="Node-RED UI Builder - Blank template">
    <link rel="icon" href="./images/node-blue.ico">

    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

</head><body>
    
    <h1>uibuilder Vega Simple Example</h1>
    <div id="view"></div>
    <pre id="msg" class="syntax-highlight">Waiting for a message from Node-RED</pre>

    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
    <script src="./uibuilderfe.min.js"></script>
    <script src="./index.js"></script>

</body></html>

```

index.js

```auto
/* eslint-disable strict */
/* jshint browser: true, esversion: 6, asi: true */
/* globals uibuilder */
// @ts-nocheck

/** Minimalist code for uibuilder and Node-RED */
'use strict'

// return formatted HTML version of JSON object
window.syntaxHighlight = function (json) {
    json = JSON.stringify(json, undefined, 4)
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
        var cls = 'number'
        if (/^"/.test(match)) {
            if (/:$/.test(match)) {
                cls = 'key'
            } else {
                cls = 'string'
            }
        } else if (/true|false/.test(match)) {
            cls = 'boolean'
        } else if (/null/.test(match)) {
            cls = 'null'
        }
        return '<span class="' + cls + '">' + match + '</span>'
    })
    return json
} // --- End of syntaxHighlight --- //

// run this function when the document is loaded
window.onload = function() {
    // Start up uibuilder - see the docs for the optional parameters
    uibuilder.start()

    const origData = [
        { "a": "A", "b": 28 }, { "a": "B", "b": 55 }, { "a": "C", "b": 43 },
        { "a": "D", "b": 91 }, { "a": "E", "b": 81 }, { "a": "F", "b": 53 },
        { "a": "G", "b": 19 }, { "a": "H", "b": 87 }, { "a": "I", "b": 52 }
    ]
    const vlJson = {
        "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
        "description": "A simple bar chart with embedded data.",
        "data": {
            //"values": origData
            "name": 'myData'
        },
        "mark": "bar",
        "encoding": {
            "x": { "field": "a", "type": "nominal", "axis": { "labelAngle": 0 } },
            "y": { "field": "b", "type": "quantitative" }
        }
    }

    // Embed visualization and save view as window.view:
    vegaEmbed('#view', vlJson).then( res => {
        res.view
            .insert('myData', origData)
            .run()

        // Save the view to window.view for later use
        window.view = res.view
    })
    //console.log(vega.changeset())

    // Listen for incoming messages from Node-RED
    uibuilder.onChange('msg', function(msg){
        console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)

        // dump the msg as text to the "msg" html element
        const eMsg = document.getElementById('msg')
        eMsg.innerHTML = window.syntaxHighlight(msg)

        var changeSet = vega
            .changeset()
            .insert(msg.payload)
            // .remove(function (t) {
            // return t.x < minimumX
            // })
        window.view.change('myData', changeSet).run().resize()

        // Changeset needs to remove everything first, then insert new data
        // let changeset = vega.changeset().remove(() => true).insert(data);
        // For some reason source_0 is the default dataset name
        // view.change('source_0', changeset).run()
    })
}

```

This is based on the Blank template. It loads a simple bar chart with data defined in the js file and then allows you to load more data from the flow. I've only added a single new data item `j`, you'll need to amend somewhat if you want to keep adding things, at the moment, if you keep inserting the data, column `j` just keeps growing.

It is clear from this example that using the vue-vega component will be benefitial. It takes care of all of the c\*\*p for you.

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [1 January 2022 21:08 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/7 "2022-01-01T21:08:38Z")

</div>

> [@TotallyInformation](#):
>
> ```auto
> const vlJson = {
> "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
> "description": "A simple bar chart with embedded data.",
> "data": {
> //"values": origData
> "name": 'myData'
> },
> "mark": "bar",
> "encoding": {
> "x": { "field": "a", "type": "nominal", "axis": { "labelAngle": 0 } },
> "y": { "field": "b", "type": "quantitative" }
> }
> }
> 
> ```

Hi,

Happy New Year to all ✨🎉👍

Julian, thank you very much for putting the effort into this. As usual, now I have even more questions, but I'll get to that later. Didn't have much time to code, but I did try creating a HTML button which would run JSONata code for random number insert, however I haven't succeded creating a working JS function for it (error was `myScript is not defined at HTMLButtonElement.onclick` - maybe only because I'm a noob in JS or uibuilder)

Now to more important issue:  
I've beed trying to create a chart using my own spec with 3 datasets, but i noticed I got the same error as you: `Uncaught (in promise) SyntaxError: Unexpected token m in JSON at position 0`, so thats why you commented the "values" parameter?

This is my data object:

```auto
        "data": [
            {
                "name": "length",
                "values": 'myData1',
                "transform": [
                    {
                        "type": "extent",
                        "field": "time",
                        "signal": "date"
                    }
                ]
            },
            {
                "name": "counter",
                "values": 'myData2'
            },
            {
                "name": "interrupts",
                "values": 'myData3'
            }
        ]

```

If I comment the values parameters then the chart don't work because I use the names afterwords in the spec..  
I haven't find any solution on google, do you have some ideas?  
This is the code I'm using to insert these default data arrays:

```auto
    vegaEmbed('#view', vlJson).then( res => {
        res.view
            .insert('myData1', origData1)
            .insert('myData2', origData2)
            .insert('myData3', origData3)
            .run()

        // Save the view to window.view for later use
        window.view = res.view
    })

```

---

<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:** [1 January 2022 23:26 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/8 "2022-01-01T23:26:20Z")

</div>

Sorry but I've never used Vega. I simply grabbed an example from their website.

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [26 January 2022 13:42 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/9 "2022-01-26T13:42:51Z")

</div>

> [@TotallyInformation](#):
>
> Sorry but I've never used Vega. I simply grabbed an example from their website.

Can you provide a link please? I can't find it...

I have managed to recreate this simple example in Vue.  
At the same time I'm trying to get everything working before I try to move to using Vega Vue component (using build step).  
Here are my questions (if anyone have time to respond):  
  
  
  
  
**1.** When using 2 or more VegaEmbed functions everything loads OK - the static datasets anyway. However when try to load data dynamicaly I get this error:  
`vega.js:123 Uncaught Error: Unrecognized data set: table`

> **Here is only this piece of the JS code**
>
> ```auto
> const origData = [
> {"x": 0, "y": 0, "c": 0}, {"x": 0, "y": 0, "c": 1},
> {"x": 1, "y": 0, "c": 0}, {"x": 1, "y": 0, "c": 1},
> {"x": 2, "y": 0, "c": 0}, {"x": 2, "y": 0, "c": 1},
> {"x": 3, "y": 0, "c": 0}, {"x": 3, "y": 0, "c": 1},
> {"x": 4, "y": 0, "c": 0}, {"x": 4, "y": 0, "c": 1},
> {"x": 5, "y": 0, "c": 0}, {"x": 5, "y": 0, "c": 1},
> {"x": 6, "y": 0, "c": 0}, {"x": 6, "y": 0, "c": 1},
> {"x": 7, "y": 0, "c": 0}, {"x": 7, "y": 0, "c": 1},
> {"x": 8, "y": 0, "c": 0}, {"x": 8, "y": 0, "c": 1},
> {"x": 9, "y": 0, "c": 0}, {"x": 9, "y": 0, "c": 1}
> ]
> 
> var origData2 = [
> {"x": 0, "y": 58, "c": 0}, {"x": 0, "y": 55, "c": 1},
> {"x": 1, "y": 43, "c": 0}, {"x": 1, "y": 91, "c": 1},
> {"x": 2, "y": 81, "c": 0}, {"x": 2, "y": 53, "c": 1},
> {"x": 3, "y": 19, "c": 0}, {"x": 3, "y": 87, "c": 1},
> {"x": 4, "y": 52, "c": 0}, {"x": 4, "y": 48, "c": 1},
> {"x": 5, "y": 24, "c": 0}, {"x": 5, "y": 49, "c": 1},
> {"x": 6, "y": 87, "c": 0}, {"x": 6, "y": 66, "c": 1},
> {"x": 7, "y": 17, "c": 0}, {"x": 7, "y": 87, "c": 1},
> {"x": 8, "y": 18, "c": 0}, {"x": 8, "y": 16, "c": 1},
> {"x": 9, "y": 49, "c": 0}, {"x": 9, "y": 15, "c": 1}
> ]
> 
> const vlJson = "bar.json"
> // Embed visualization and save view as window.view:
> vegaEmbed('#view', vlJson).then( res => {
> res.view
> .insert('table', origData)
> .run()
> // Save the view to window.view for later use
> window.view = res.view
> })
> 
> const vlJson2 = "bar2.json"       
> vegaEmbed('#view2', vlJson2).then( res => {
> res.view
> .insert('table2', origData2)
> .run()
> // Save the view to window.view for later use
> window.view = res.view
> })
> //console.log(vega.changeset())
> 
> uibuilder.onChange('msg', function(msg){
> console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
> app.msgRecvd = msg
> app.msgsReceived = uibuilder.get('msgsReceived')
> app.lastMsg = msg
> 
> var changeSet = vega
> .changeset()
> .insert(msg.payload)
> // .remove(function (t) {
> // return t.x < minimumX
> // })
> window.view.change('table', changeSet).run().resize()
> 
> // Changeset needs to remove everything first, then insert new data
> // let changeset = vega.changeset().remove(() => true).insert(data);
> // For some reason source_0 is the default dataset name
> // view.change('source_0', changeset).run()
> })
> 
> ```

I cant find the link on the web and I have no Idea whats wrong and how to solve this..

**2.** I tried load the JSON using fetch like @UnborN suggested but I don't know JS good and I can't seem to find the solution on the web.

> [@Uibuilder error 404 (not found)](https://discourse.nodered.org/t/uibuilder-error-404-not-found/56919/12):
>
> also what do you expect to happen with this line ?  
> `const vlJson = "bar.json"`  
> read and load the bar.json file ?  
> ([look into using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) or better send the bar.json file from Node-red to uibuilder and then trigger the draw of the chart )

I've tried this:

```auto
        var vlJson2;
        fetch("bar.json")
        .then((response) => {
          return response.json();
        })
        .then(data => console.log(data))
        .then((data) => {
            var vlJson2 = data;
        })

```

but `vlJson2` isn't usable outside the callback.

I've also tried this:

```auto
//var vlJson2;
fetch("bar.json")
.then((response) => {
  return response.json();
})
.then(data => console.log(data))
.then((data) => {
    //var vlJson2 = data;
    vegaEmbed('#view2', data).then( res => {
        res.view
            .insert('table2', origData2)
            .run()
        // Save the view to window.view for later use
        window.view = res.view
    })
})

```

But it gave me error:  
`Uncaught (in promise) TypeError: Cannot read properties ` at chart load.

**3.** This part I still dont understand. Is it only me or does anyone else have this kind of problems?

> [@Uibuilder error 404 (not found)](https://discourse.nodered.org/t/uibuilder-error-404-not-found/56919/13):
>
> Vega and Vega-lite are both available as npm packages. That means that you can use uibuilder to serve the code.

> [@Uibuilder error 404 (not found)](https://discourse.nodered.org/t/uibuilder-error-404-not-found/56919/15):
>
> There are examples of using similar libraries in the WIKI. Start with using the CDN versions so you know that it is working. Then Install the libraries using the library manager and follow the instructions for finding the right URL.

> [@Node-RED projects + uibuilder: How to include installation of vue, bootstrap, bootstrap-vue?](https://discourse.nodered.org/t/node-red-projects-uibuilder-how-to-include-installation-of-vue-bootstrap-bootstrap-vue/43898/2):
>
> Hi Michael, there are two places where you need the list of installed libraries. ~/.node-red/package.json - required for the npm package installation ~/.node-red/uibuilder/.config/packageList.json - required so that uibuilder knows which installed packages to serve up using its web server. I think (though I don't use projects so I'm a little vague on memory sorry) that the uibuilder folder is under the project folder. ~/.node-red/projects/\<projectName\>/uibuilder/.config/packageList.json. Ho…

So, ATM I just copy-pasted the JS vega files to the static folder and I'm loading them from there.  
You're saying its better to install them using NPM? like `npm i vega-embed` and then load to them to the uibuilder? How? I have all the uibuilder examples installed but I've only found this:

```auto
    <!-- Loading from CDN, use uibuilder to install packages and change to vendor links -->
    <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-apexcharts"></script>

```

---

<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:** [26 January 2022 15:06 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/10 "2022-01-26T15:06:41Z")

</div>

> [@nerevar](#):
>
> Can you provide a link please? I can't find it...

[Simple Bar Chart | Vega-Lite](https://vega.github.io/vega-lite/examples/bar.html)

> [@nerevar](#):
>
> `fetch("bar.json")`

The problem is, how does your browser know the full URL of that file? It needs to be served by something. And whatever is serving it will define the URL you need to use. You can serve static files from uibuilder of course. The simple way being to put the file into the same folder as your `index.` files. Then the URL will be `./bar.json` - note the leading `./`, your browser will translate that to `http://yournoderedserverip:1880/your-uib-url/bar.json` or something similar. using that relative format means that if you need to move your code to a different server or turn on https or change the node-red port to something different, you don't have to edit your code, it will still work.

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [27 January 2022 08:27 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/11 "2022-01-27T08:27:20Z")

</div>

I'm sorry, but I wasn't asking that.

The link you provided does not contain this code:

```auto
        var changeSet = vega
            .changeset()
            .insert(msg.payload)
            // .remove(function (t) {
            // return t.x < minimumX
            // })
        window.view.change('myData', changeSet).run().resize()

```

But basic chart parameters. I've been working with parameters for a month total, so I happen to know them really well...

The other answer also does not explain how do you "install and use the library using uibuilder"....

I know you're busy - I'll try to look for the answers myself.

---

<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:** [27 January 2022 13:28 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/12 "2022-01-27T13:28:43Z")

</div>

> [@nerevar](#):
>
> The link you provided does not contain this code

Ah OK, maybe I came up with some of that myself. `.insert(msg.payload)` is the uibuilder bit of course and is hopefully pretty self-evident?

> [@nerevar](#):
>
> how do you "install and use the library using uibuilder"

Installation of libraries to use in your front-end code is done in uibuilder via the package/library manager. It uses npm behind the scenes to install the packages in the same way as you would do things manually. But it then goes on to add the relavent folders to the ExpressJS web server on the `../uibuilder/vendor/<pkgname>/` url path. That way you can include them as link or script url's in your index.html file in the same way that the [socket.io](http://socket.io) library is loaded.

---

<div class="post-metadata">

**Author:** ![nerevar](https://avatars.discourse-cdn.com/v4/letter/n/f475e1/32.png) [@nerevar](https://discourse.nodered.org/u/nerevar)\
**Post date:** [30 January 2022 08:54 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/13 "2022-01-30T08:54:50Z")

</div>

OK I've managed to get everyting working properly using vue.  
I wasn't using fetch because this JSON file is the chart spec not data, so it only needs to load once on startup.  
Also, a multiple charts can be made with only 1 spec - `res.view` needs to be saved at different `window` var (e.g. `window.view2 = res.view`)

> **js**
>
> methods:
> 
> ```auto
> methods: {
> 
> dataLoad: function() {
> console.log('Button Pressed.')
> uibuilder.send( {
> topic: 'load'
> })
> },
> dataLoad2: function() {
> console.log('Button Pressed.')
> uibuilder.send( {
> topic: 'load2'
> })
> },
> dataReset: function() {
> console.log('Reset.')
> uibuilder.send( {
> topic: 'reset'
> })
> },
> 
> ```
> 
> mounted:
> 
> ```auto
> function startup() {
> //console.log(origData2)            
> const vlJson = "bar.json"
> // Embed visualization and save view as window.view:
> vegaEmbed('#view', vlJson).then( res => {
> res.view
> .insert('table', origData)
> .run()
> // Save the view to window.view for later use
> window.view = res.view
> })
> vegaEmbed('#view2', vlJson).then( res => {
> res.view
> .insert('table', origData2)
> .run()
> window.view2 = res.view
> })
> }
> startup();
> 
> uibuilder.onChange('msg', function(msg){
> console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
> app.msgRecvd = msg
> app.msgsReceived = uibuilder.get('msgsReceived')
> app.lastMsg = msg
> 
> if (msg.topic === 'chart_data') {
> let changeSet = vega
> .changeset()
> .insert(msg.payload)
> window.view.change('table', vega.changeset().insert(msg.payload).remove(view.data('table').slice(0,2))).run()//.resize()
> //remove(function (t) { return t.y1 < 2; })
> //view.remove('table', d => d.count < 5).run();
> }
> else if (msg.topic === 'chart_data2') {
> let changeset = vega
> .changeset()
> .remove(() => true)
> .insert(msg.payload)
> view2.change('table', changeset).run()
> }
> else if (msg.topic === 'reset') startup()
> })
> 
> ```

One more question. How to send message to itself - using methods.  
So I have buttons on my html and I want to make a method to send a message to a `mounted` function `uibuilder.onChange` **without having to send it out to the node-red**. (for testing purposes)

I've tried setting this to to mounted:

```auto
        dataLoad3: function() {
            console.log('Button Pressed.')
            uibuilder.set( {
                payload: { "x": 0, "y": 20, "c":0 },
                topic: 'chart_data3'
            })
        },

```

but then I dont know to how to pickup the change:

```auto
        uibuilder.onChange(get, function(msg){
            console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
            app.msgRecvd = msg
            app.msgsReceived = uibuilder.get('msgsReceived')
            app.lastMsg = msg

        if (msg.topic === 'chart_data3') {
                let changeset = vega
                    .changeset()
                    .remove(() => true)
                    .insert(msg.payload)
                view3.change('table', changeset).run()
            }
        })

```

---

<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:** [30 January 2022 11:49 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/14 "2022-01-30T11:49:48Z")

</div>

> [@nerevar](#):
>
> I wasn't using fetch because this JSON file is the chart spec not data, so it only needs to load once on startup.

You could always use the connect control msg that comes out of uibuilder's port 2 when a client connects - to send that data using a msg.

> [@nerevar](#):
>
> methods:

You could probably collapse those 3 down to a single method with a parameter.

> [@nerevar](#):
>
> One more question. How to send message to itself - using methods.  
> So I have buttons on my html and I want to make a method to send a message to a `mounted` function `uibuilder.onChange` **without having to send it out to the node-red**. (for testing purposes)

You can, and probably should, use a method attached to the onClick event of the button. There is an example in one of the Vue templates in uibuilder.

In the method, you could have a switch variable that lets you dump to console instead of actually sending.

It _is_ also possible to "send" a msg that appears to uibuilder as though it has come from Node-RED if that is what you want. `uibuilder.set('msg',{payload:'hello'})`

> [@nerevar](#):
>
> I've tried setting this to to mounted:

Close, but you didn't tell `set` what variable to change.

> [@nerevar](#):
>
> but then I dont know to how to pickup the change:

You don't need to do anything special if you set the `msg` variable, that triggers any event listeners in the same way that a message from Node-RED would.

In fact, you can register a listener on ANY uibuilder variable that is a managed one. Just by using `uibuilder.onChange('varname', function(newVal) { ... })`. Using `set` ensures that the variable is managed so you can create new variables as well as long as you avoid the reserved names. However, you don't really need to do that if you are using Vue, better to use Vue's managed data variables.

---

<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:** [13 February 2022 11:50 UTC](https://discourse.nodered.org/t/uibuilder-vega-chart-and-db-s-integration/55611/15 "2022-02-13T11:50:42Z")

</div>

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