Skip to content

Integrating ApexCharts with VueJS

Julian Knight edited this page Oct 15, 2022 · 6 revisions

UPDATE 2022-10-15 - The example below only updates the Pie chart. If you want to update a more complex chart such as bar or line, the ApexChart series data is more complex than VueJS recalculate options can deal with. The reasons are explained here: https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays. To get round that, either force VueJS to update or replace the whole series:

        uibuilder.onChange('msg', function (newVal) {
            if ( typeof newVal.payload === 'number' ){
                const data = vueApp.dseries[0].data
                data.push(newVal.payload)
                data.shift()
                vueApp.dseries = [{ data: data }]
            }
        })

UPDATE 2021-03-01 - I've had reports that ApexCharts doesn't work with Android Chrome or Android Firefox.


Here is an example of how to use ApexCharts with the default uibuilder v2 installation to add a simple chart.

Add an instance of uibuilder to your flows and replace the index.html and index.js files with the code below.

I'm loading the chart libraries using a CDN here, the next step would be to install the two packages using uibuilder's npm interface.

The example flow sends a random number to the app every 10 seconds which is used to update the donut chart.

Note that the following flow also includes 2 comment nodes containing the html and javascript

flow

[{"id":"df81cc9e.a9171","type":"inject","z":"18cb249f.38bafb","name":"repeat every 10s","topic":"","payload":"","payloadType":"date","repeat":"10","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":80,"wires":[["6ca36476.d0597c"]]},{"id":"76678044.5aaeb","type":"debug","z":"18cb249f.38bafb","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":650,"y":60,"wires":[]},{"id":"bd9b5761.fb4918","type":"debug","z":"18cb249f.38bafb","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":630,"y":100,"wires":[]},{"id":"b18a50dd.f7e5c","type":"uibuilder","z":"18cb249f.38bafb","name":"","topic":"","url":"chart","fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"showfolder":false,"x":490,"y":80,"wires":[["76678044.5aaeb"],["bd9b5761.fb4918"]]},{"id":"6ca36476.d0597c","type":"change","z":"18cb249f.38bafb","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"($random()*10)+($random()*10)\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":80,"wires":[["b18a50dd.f7e5c"]]},{"id":"3ebfbce9.6ccd84","type":"comment","z":"18cb249f.38bafb","name":"html","info":"copy the following and paste into `index.html`\n\n```html\n<!doctype html><html lang=\"en\"><head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes\">\n\n    <title>ApexChart/VueJS Example - Node-RED UI Builder</title>\n    <meta name=\"description\" content=\"Node-RED UI Builder - ApexChart/VueJS Example\">\n\n    <link rel=\"icon\" href=\"./images/node-blue.ico\">\n\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"../uibuilder/vendor/bootstrap/dist/css/bootstrap.min.css\" />\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css\" />\n\n    <link rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n</head><body>\n    <div id=\"app\">\n        <b-container id=\"app_container\">\n\n            <h1>\n                Examples of using <a href=\"https://apexcharts.com/docs/vue-charts/\" target=\"_blank\">ApexChart</a>\n                with uibuilder, VueJS and bootstrap-vue\n            </h1>\n\n            <b-row>\n                <b-card col class=\"w-50\" header=\"Bar Chart\" border-variant=\"primary\" header-bg-variant=\"primary\" header-text-variant=\"white\" align=\"center\">\n                        <apexchart width=\"100%\" type=\"bar\" :options=\"options\" :series=\"series\"></apexchart>\n                </b-card>\n\n                <b-card col class=\"w-50\" header=\"Donut Chart\" border-variant=\"primary\" header-bg-variant=\"primary\" header-text-variant=\"white\" align=\"center\">\n                        <apexchart width=\"100%\" type=\"donut\" :options=\"doptions\" :series=\"dseries\"></apexchart>\n                </b-card>\n            </b-row>\n\n        </b-container>\n    </div>\n\n    <script src=\"../uibuilder/vendor/socket.io/socket.io.js\"></script>\n    <script src=\"../uibuilder/vendor/vue/dist/vue.min.js\"></script>\n    <script src=\"../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js\"></script>\n\n    <!-- Loading from CDN, use uibuilder to install packages and change to vendor links -->\n    <script src=\"https://cdn.jsdelivr.net/npm/apexcharts\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/vue-apexcharts\"></script>\n\n    <script src=\"./uibuilderfe.min.js\"></script> <!--    //prod version -->\n    <script src=\"./index.js\"></script>\n\n</body></html>\n\n```","x":370,"y":40,"wires":[]},{"id":"7254bbb9.903ce4","type":"comment","z":"18cb249f.38bafb","name":"JavaScript","info":"Copy the following and paste into `index.js`\n\n```javascript\n/* jshint browser: true, esversion: 5 */\n/* globals document,Vue,window,uibuilder,VueApexCharts */\n// @ts-nocheck\n/*\n  Copyright (c) 2019 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n'use strict'\n\n/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */\n\n/** Reference the apexchart component (removes need for a build step) */\nVue.component('apexchart', VueApexCharts)\n\n// eslint-disable-next-line no-unused-vars\nvar app1 = new Vue({\n    el: '#app',\n    data: {\n        startMsg    : 'Vue has started, waiting for messages',\n\n        // Data for bar chart\n        options: {\n            chart: {\n                id: 'vuechart-example'\n            },\n            xaxis: {\n                categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998]\n            }\n        },\n        series: [{\n            name: 'series-1',\n            data: [30, 40, 45, 50, 49, 60, 70, 91]\n        }],\n\n        // Data for donut chart\n        doptions: {},\n        dseries: [44, 55, 41, 17, 15]\n\n    }, // --- End of data --- //\n    computed: {\n    }, // --- End of computed --- //\n    methods: {\n    }, // --- End of methods --- //\n\n    // Available hooks: init,mounted,updated,destroyed\n    mounted: function(){\n        /** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3\n         * Pass the namespace and ioPath variables if hosting page is not in the instance root folder\n         * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.\n         * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names\n         */\n        uibuilder.start()\n\n        var vueApp = this\n\n        // Process new messages from Node-RED\n        uibuilder.onChange('msg', function (newVal) {\n            if ( typeof newVal.payload === 'number' ){\n                // Add new element\n                vueApp.dseries.push(newVal.payload)\n                // Lose the first element\n                vueApp.dseries.shift()\n                //console.log(vueApp.dseries)\n            }\n        })\n\n    } // --- End of mounted hook --- //\n\n}) // --- End of app1 --- //\n\n// EOF\n```\n","x":480,"y":40,"wires":[]}]

html

<!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>ApexChart/VueJS Example - Node-RED UI Builder</title>
    <meta name="description" content="Node-RED UI Builder - ApexChart/VueJS 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>
                Examples of using <a href="https://apexcharts.com/docs/vue-charts/" target="_blank">ApexChart</a>
                with uibuilder, VueJS and bootstrap-vue
            </h1>

            <b-row>
                <b-card col class="w-50" header="Bar Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                        <apexchart width="100%" type="bar" :options="options" :series="series"></apexchart>
                </b-card>

                <b-card col class="w-50" header="Donut Chart" border-variant="primary" header-bg-variant="primary" header-text-variant="white" align="center">
                        <apexchart width="100%" type="donut" :options="doptions" :series="dseries"></apexchart>
                </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://cdn.jsdelivr.net/npm/apexcharts"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-apexcharts"></script>

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

</body></html>

JavaScript

/* jshint browser: true, esversion: 5 */
/* globals document,Vue,window,uibuilder,VueApexCharts */
// @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 */

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

// eslint-disable-next-line no-unused-vars
var app1 = new Vue({
    el: '#app',
    data: {
        startMsg    : 'Vue has started, waiting for messages',

        // Data for bar chart
        options: {
            chart: {
                id: 'vuechart-example'
            },
            xaxis: {
                categories: [1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998]
            }
        },
        series: [{
            name: 'series-1',
            data: [30, 40, 45, 50, 49, 60, 70, 91]
        }],

        // Data for donut chart
        doptions: {},
        dseries: [44, 55, 41, 17, 15]

    }, // --- 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) {
            if ( typeof newVal.payload === 'number' ){
                // Add new element
                vueApp.dseries.push(newVal.payload)
                // Lose the first element
                vueApp.dseries.shift()
                //console.log(vueApp.dseries)
            }
        })

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

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

// EOF
Clone this wiki locally