# Using Chart.js to show charts

**URL:** <https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498>\
**Category:** Dashboard\
**Created:** [30 January 2022 12:23 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498 "2022-01-30T12:23:58Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 12:23 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/1 "2022-01-30T12:23:58Z")

</div>

Hi  
I worked on OpenHab with Chart.js before.  
So I thought to use chart.js on nodeRed dashboard as well.  
I found some projects doing so.  
[https://flows.nodered.org/flow/c3dc75c47323a2754f5285225bce64b5](https://flows.nodered.org/flow/c3dc75c47323a2754f5285225bce64b5)  
and  
[https://flows.nodered.org/flow/720044a3c587a310813a9326ed3cb08a](https://flows.nodered.org/flow/720044a3c587a310813a9326ed3cb08a)  
Basicaly they worked. I see the chart in dashboardUI

But for editing the code for my needs, I would like to have this JS code not in a function Node in NodeRed, but in a seperate file.  
I configured httpStatic: and placed the js file there.  
In a functionnode I placed

```auto
<script src="/test/js/Chart.bundle.min.js"></script>
<canvas id="myChartSimple1" width="300" height="300"></canvas>
<script src="/test/js/test.js"></script>

```

When I explore the Network with the browser, both files are found and loaded, but  
nothing happens.

The Node in dashboardUI leaves blank.

where is my fault, what can I change?  
Thank you!

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2022 12:26 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/2 "2022-01-30T12:26:08Z")

</div>

> [@goony](#):
>
> In a functionnode I placed
> 
> ```auto
> <script src="/test/js/Chart.bundle.min.js"></script>
> <canvas id="myChartSimple1" width="300" height="300"></canvas>
> <script src="/test/js/test.js"></script>
> 
> ```

Putting html in a function node will not create a web page.

Perhaps you are using the wrong terms? Did you mean a ui-template node?

---

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 13:19 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/3 "2022-01-30T13:19:24Z")

</div>

> [@Steve-Mcl](#):
>
> Did you mean a ui-template node?

Of course. Sorry.  
ui-template node !!!

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2022 13:37 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/4 "2022-01-30T13:37:18Z")

</div>

litter your `/test/js/test.js` with `console.log("this is the value of x", x)` and `console.log("inside function DrawMyChart'')` etc

deploy

refresh the browser

do you see these log entries?

---

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 14:06 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/5 "2022-01-30T14:06:54Z")

</div>

> [@Steve-Mcl](#):
>
> deploy  
> refresh the browser  
> do you see these log entries?

I did edit the test.js. Every function got an console.log

But there are no console logs

 ![Screenshot from 2022-01-30 15-03-08](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/1/d13e86744914cb5cd43cb5be7cd241b7ddc172e7.png)  
You can see, the file itself is called and deployed?  
but no console logs.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2022 14:29 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/6 "2022-01-30T14:29:07Z")

</div>

Just because a js file loads doesn't mean the code is executed. You would need to share the code for me to understand why.

---

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 14:33 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/7 "2022-01-30T14:33:02Z")

</div>

It's the code from [Add Chart.js charts to node-red-dashboard flows (flow) - Node-RED](https://flows.nodered.org/flow/720044a3c587a310813a9326ed3cb08a)

The first "alert" and console log are working  
alert("Beginn")  
console.log("inside Beginn")

```auto
alert("Beginn")  
console.log("inside Beginn")
(function() {
	alert("vardef")  
 	console.log("inside function vardef")
   var chartID = "myChartSimple1"; // set this to the id you have specified in the canvas tag above
    // setup the chart definition as defined in the chart.js documentation, in addition setting up the topic
    // for each channel
    var chartDef = {
        type: 'line',
        data: {
            datasets: [{
                topic: "Sin", // used here not by chart.js
                label: "Sin",
                yAxisID: "1",
                fill: false,
                lineTension: 0,
                borderColor: "#0000ff",
                pointRadius: 5,
                pointHoverRadius: 5,
                pointBorderColor: "#0000ff",
                pointBackgroundColor: "#0000ff",
                backgroundColor: "#0000ff",
                borderWidth: 1,
                data: [] // data is written here later
            }, {
                topic: "Triangle", // used here not by chart.js
                label: "Triangle",
                yAxisID: "2",
                fill: false,
                lineTension: 0,
                borderColor: "#ff0000",
                pointRadius: 5,
                pointHoverRadius: 5,
                pointBorderColor: "#ff0000",
                pointBackgroundColor: "#ff0000",
                backgroundColor: "#ff0000",
                borderWidth: 1,
                data: [] // data is written here later
            }]
        },
        options: {
            scales: {
                xAxes: [{
                    type: 'linear',
                    position: 'bottom'
                    }
                ],
                yAxes: [{
                    id: "1",
                    ticks: {
                        min: -1,
                        max: 1,
                        stepSize: 0.2
                    }
                }, {
                    id: "2",
                    ticks: {
                        min: -10,
                        max: 10,
                        stepSize: 2
                    }
                }]
            },
            animation: {
                duration: 0
            }
        }
    }
        
/ *****You shouldn't normally need to change anything below here***** /    
    var myChart = null;
    var loaded = false; // indicates whether we have already had a load action
    var chartTimeSpan;
    var chartMaxPoints;

    function doChart(msg, scope) {
		alert("doChart")  
		console.log("inside function doChart")
        if (!myChart) {
            // chart does not exist so load the data and create it
            var ctx = document.getElementById(chartID);
            myChart = new Chart(ctx, chartDef);     
        }
        // chart already exists, update it
        var datasets = myChart.data.datasets;
        // is this a load or preload action?
        if (msg.action === "load" || msg.action === "preload") {
            // yes, do not allow preload if we have already had a load
            // so do it if this is a load or we have not previously had a load
            if (msg.action === "load" || !loaded) {
                // pick up chartTimeSpan and chartMaxPoints if they have been provided
                if (typeof msg.chartTimeSpan != 'undefined') {
                    chartTimeSpan = msg.chartTimeSpan;
                }
                if (typeof msg.chartMaxPoints != 'undefined') {
                    chartMaxPoints = msg.chartMaxPoints;
                }
                    
                // replace existing data for matching topics
                for (var j = 0; j < msg.payload.length; j++) {
                    var topic = msg.payload[j].topic;
                    // find it in the chart
                    for (var i = 0; i < datasets.length; i++) {
                        if (datasets[i].topic == topic) {
                            // if stripping old samples by time is required then ensure the x value is Date
                            if (chartTimeSpan > 0 ) {
                                var data = msg.payload[j].data;
                                for (var k = 0; k < data.length; k++) {
                                    if (typeof data[k].x === "string") {
                                        data[k].x = new Date(data[k].x);
                                    }
                                }
                            }
                            if (chartDef.type !== "bar") {
                                datasets[i].data = msg.payload[j].data;
                            } else {
                                // bar chart so x values must go to labels and y values to dataset
                                datasets[i].data = [];
                                myChart.data.labels = [];
                                var data = msg.payload[j].data;
                                for (var k = 0; k < data.length; k++) {
                                    datasets[i].data.push(data[k].y);
                                    myChart.data.labels.push(data[k].x);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            if (msg.action === "load") loaded = true;
            myChart.update();
        } else {
            // does the topic match one of the datasets?
            for (var i = 0; i < datasets.length; i++) {
                if (datasets[i].topic == msg.topic) {
                    // if stripping old samples by time is required then ensure the x value is Date
                    if (chartTimeSpan > 0 && typeof msg.payload.x === "string") {
                        msg.payload.x = new Date(msg.payload.x);
                    }
                    if (chartDef.type !== "bar") {
                        datasets[i].data.push(msg.payload);
                    } else {
                         // bar chart so x value must go to labels and y value to dataset
                        datasets[i].data.push(msg.payload.y);
                        myChart.data.labels.push(msg.payload.x);
                    }
                    myChart.update();
                    break;
                }
            }
        }
        // strip off samples older than now
        // charTimeSpan == 0 implies don't do it
        var shifted = false;
        if (chartTimeSpan > 0) {
            var now = new Date();
            var oldestTimeAllowed = now - chartTimeSpan;
            for (var i = 0; i < datasets.length; i++) {
                dataset = datasets[i];
                while(dataset.data[0] && getTime(dataset.data[0].x) < oldestTimeAllowed) {
                    dataset.data.shift();
                    shifted = true;
                }
            }
        }
        // strip samples off the front if there are now too many
        // charTimeSpan == 0 implies don't do it
        if (chartMaxPoints > 0) {
            for (var i = 0; i < datasets.length; i++) {
                dataset = datasets[i];
                while(dataset.data.length > chartMaxPoints) {
                    dataset.data.shift();
                    shifted = true;
                }
            }
        }
        if (shifted) {
            myChart.update();
        }
    };

    // gets the time of an x value, works for strings or Date types
    function getTime(x) {
		alert("getTime")  
		console.log("inside function getTime")
        if (typeof x === "string") x = new Date(x);
        return x.getTime();
    }
    
    // builds the preload message for sending back to the chart helper
    function preloadMsg() {
		alert("preloadMsg")  
		console.log("inside function preloadMsg")
        var preMsg = {action: "preload", payload: "preload"};
        // build array of topics in chart
        var topics = [];
        for (var i=0; i<chartDef.data.datasets.length; i++) {
            topics.push(chartDef.data.datasets[i].topic);
        }
        preMsg.topics = topics;
        // has the chart already been created
        if (myChart) {
            preMsg.lastXValue = 1;
        } else {
            preMsg.lastXValue = 0;
        }
        return preMsg;
    }

    (function(scope) {
        // this code gets run when the a view is opened on the node in the browser
        // send a preload message back to node red to ask it send
        // us a complete set of data. Pass down max points and time span to the helper node for it to use
        // plus an array of the topics of interest
        scope.send( preloadMsg() );
        
        scope.$watch('msg', function(msg) {
            if (msg) {
                doChart(msg, scope);
            }
        });
    })(scope);
})();

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2022 14:38 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/8 "2022-01-30T14:38:37Z")

</div>

try this...

```auto
alert("Beginn")  
console.log("inside Beginn")
(function() { // <<<<<<< DELETE THIS LINE
	alert("vardef")  
 	console.log("inside function vardef")

// code snipped for brevity

    (function(scope) {
// code snipped for brevity
    })(scope);
})(); // <<<<<<< DELETE THIS LINE

```

Also, I'm not sure ` (function(scope) {` will work in an include

You may need to put this part in the UI Template

```auto
<script src="/test/js/Chart.bundle.min.js"></script>
<canvas id="myChartSimple1" width="300" height="300"></canvas>
<script src="/test/js/test.js"></script>
<script>
    (function(scope) {
        // this code gets run when the a view is opened on the node in the browser
        // send a preload message back to node red to ask it send
        // us a complete set of data. Pass down max points and time span to the helper node for it to use
        // plus an array of the topics of interest
        scope.send( preloadMsg() );
        
        scope.$watch('msg', function(msg) {
            if (msg) {
                doChart(msg, scope);
            }
        });
    })(scope);
</script>

```

Completely untested ↑

You will need to figure out how it fits together.

---

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 14:42 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/9 "2022-01-30T14:42:33Z")

</div>

> [@Steve-Mcl](#):
>
> `(function() { // <<<<<<< DELETE THIS LINE`

Yes your'e right - it works.  
But why does a IIFE ( Immediately Invokable Function Expression ) not work?  
I'm not so familiar with javascript.  
Thank you!!

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [30 January 2022 15:04 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/10 "2022-01-30T15:04:51Z")

</div>

It does work, the problem is an IIFE is called only once meaning the scope IIFE `(function(scope) {` can never be called because of initialisation timing.

---

<div class="post-metadata">

**Author:** ![goony](https://avatars.discourse-cdn.com/v4/letter/g/59ef9b/32.png) [@goony](https://discourse.nodered.org/u/goony)\
**Post date:** [30 January 2022 15:13 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/11 "2022-01-30T15:13:57Z")

</div>

> [@Steve-Mcl](#):
>
> can never be called because of initialisation timing.

I see. I always got the data in my chart.js on other projects by ajax-calls and php. I think I have to do it different in NodeRed. I will figure it out.  
Thank you very much !!!!!

---

<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 15:14 UTC](https://discourse.nodered.org/t/using-chart-js-to-show-charts/57498/12 "2022-02-13T15:14:03Z")

</div>

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