SteppedLine Chart together with Line Chart

Thanks hotNipi ! :slight_smile: Now Working ! I will do now all my UI-graphs into a UI template :slight_smile:
Anyways.. Do you have any recommendations regarding the Chart.js tutorial? Or just their official documentation will do? THanks Buddy!

You can safely rely on documentation. That is what I do almost always.

Hello hotNipi,

Dont know what is the problem with my code:

[{"id":"8aa16d81.d126a","type":"ui_template","z":"c5297e70.44a6f","group":"35195b4c.6627d4","name":"","order":1,"width":"15","height":"5","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":820,"y":340,"wires":[[]]},{"id":"50873831.445ab8","type":"template","z":"c5297e70.44a6f","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"annualChart\" width=\"600\" height=\"400\"></canvas>\n<script>\nvar ctx = document.getElementById('annualChart').getContext('2d');\nnew Chart(ctx, {\n    type: 'line',\n    data: {\n        labels: [],\n        datasets: [\n            {\n                type:'line',\n                label: 'Annual Target',\n                backgroundColor: rgba(44, 160, 44, 0.85),\n                data: [{{payload.data}}]\n            }\n            ]\n    },\n     options: {\n        scales: {\n            xAxes: [{\n                type: 'time',\n                time: {\n                    unit: 'month'\n                }\n            }]\n        }\n    }\n});\n</script>","output":"str","x":520,"y":340,"wires":[["8aa16d81.d126a","544421db.68442"]]},{"id":"544421db.68442","type":"debug","z":"c5297e70.44a6f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":750,"y":300,"wires":[]},{"id":"5e8547a1.50e328","type":"function","z":"c5297e70.44a6f","name":"","func":"\nvar m_actual = []\nvar startTime = 1577836800000\nfor(x=1;x<=365;x++){\n    var new_msg_actual = {\"x\": startTime, \"y\": Math.random() * 300}\n    m_actual.push(new_msg_actual)\n    startTime += 86400000\n}\nmsg.payload = {\n    \"data\": m_actual\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":330,"y":340,"wires":[["50873831.445ab8","78ea598.0f04ca8"]]},{"id":"8a4b27bd.8980d8","type":"inject","z":"c5297e70.44a6f","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":340,"wires":[["5e8547a1.50e328"]]},{"id":"78ea598.0f04ca8","type":"debug","z":"c5297e70.44a6f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":550,"y":420,"wires":[]},{"id":"35195b4c.6627d4","type":"ui_group","z":"","name":"Annual Target ","tab":"e69d5cf5.b9796","order":1,"disp":true,"width":"15","collapse":false},{"id":"e69d5cf5.b9796","type":"ui_tab","z":"","name":"TIWI Asset KPI","icon":"dashboard","order":2,"disabled":false,"hidden":false}]

Kindly troubleshoot this :frowning: in debug message the "data" only appears as Object .....

Thanks! Hoping for your response..

Look at the output of the template node, what do you notice? Compare that to the flow you have earlier that works (stick a debug node of the output of that template node)

What is the difference?

It seems like the Template node can't get the Data right from another node.
I have functions that creates an array of object [{x: 1238091823, y: 25}...] , this object will pass on the template node, however template node see this object as [[object, object], [object,object]]... That is why my graph is nothing because this should be the datasets.
I dont know the template node will read my array of object .

Generate data to be json string


var m_actual = []
var startTime = 1577836800000
for(x=0;x<365;x++){
    var new_msg_actual = {"x": startTime, "y": Math.random() * 300}
    m_actual.push(new_msg_actual)
    startTime += 86400000
}
msg.payload = JSON.stringify(m_actual)

return msg;

And use the payload in template:

 data:{{{payload}}}

Edit: My phone typing was terrible - but thanks to @zenofmud fixes applied

1 Like

Thanks to all of you! :slight_smile:
I can now see the JSON object to my template..
However, still has no graphs :frowning:
Did I miss something on the "Options" side of XAxis?

 <canvas id="myChart" width=600 height =400></canvas>
<script>
    var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
    // The type of chart we want to create
    type: 'line',

    // The data for our dataset
    data: {
        labels: [],
        datasets: [{
            label: 'My First dataset',
            backgroundColor: ['Green'],
            //data: [-5, 10, 5],
            data: {{{payload}}}
            yAxisID: 'right-y-axis',
            steppedLine: true,
            fill: false,
            borderColor: ['Green'],
            borderWidth: 3
        },
       
        ]
       
    },

    // Configuration options go here
    options: {
        scales: {
            xAxes: [{
                type: 'time',
                distribution: 'series'
            }]
        }
    }
});
</script>

Thanks again buddy !

OMG! Just missing a comma and few Options!
It is now working ! Thanks Buddy !

[{"id":"957b298d.334ed8","type":"ui_template","z":"c6ca63bb.080ba","group":"80d77992.39c8e8","name":"Line Chart","order":4,"width":"15","height":"15","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":710,"y":180,"wires":[[]]},{"id":"1b809d8e.a34272","type":"inject","z":"c6ca63bb.080ba","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":180,"wires":[["576d31f9.b0d72"]]},{"id":"576d31f9.b0d72","type":"function","z":"c6ca63bb.080ba","name":"","func":"\nvar m_actual = []\nvar startTime = 1577836800000\nfor(x=1;x<=365;x++){\n    var new_msg_actual = {x: new Date(startTime), y: Math.random() * 300}\n    m_actual.push(new_msg_actual)\n    startTime += 86400000\n}\nmsg.payload = JSON.stringify(m_actual)\nreturn msg;\n","outputs":1,"noerr":0,"x":330,"y":160,"wires":[["51f6b098.faa0f"]]},{"id":"99ff25f6.6486b8","type":"debug","z":"c6ca63bb.080ba","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":690,"y":260,"wires":[]},{"id":"51f6b098.faa0f","type":"template","z":"c6ca63bb.080ba","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =400></canvas>\n<script>\n    var ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [{\n            label: 'My First dataset',\n            backgroundColor: ['Green'],\n            //data: [-5, 10, 5],\n            data: {{{payload}}},\n            yAxisID: 'right-y-axis',\n            steppedLine: true,\n            fill: false,\n            borderColor: ['Green'],\n            borderWidth: 3\n        },\n       \n        ]\n       \n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [{\n                id: 'left-y-axis',\n                type: 'linear',\n                position: 'left'\n            }, {\n                id: 'right-y-axis',\n                type: 'linear',\n                position: 'right'\n            }],\n            xAxes: [{\n                type: 'time',\n                distribution: 'series'\n            }]\n        }\n    }\n});\n</script>\n","output":"str","x":500,"y":160,"wires":[["957b298d.334ed8","99ff25f6.6486b8"]]},{"id":"80d77992.39c8e8","type":"ui_group","z":"","name":"Chart","tab":"8962ad11.78ab2","order":3,"disp":true,"width":"15","collapse":false},{"id":"8962ad11.78ab2","type":"ui_tab","z":"","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
1 Like

I think you'll have errors in console cos colors in dataset cant be provided in array.
Use hex string backgroundColor: '#009900', borderColor: '#009900'

Added some styling tricks, to force chart render according to the dashboard styles

[{"id":"26d66b9b.186034","type":"ui_template","z":"5f1bed63.cb2a94","group":"304730.1de8e8d","name":"Line Chart","order":4,"width":"15","height":"10","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":640,"y":280,"wires":[[]]},{"id":"29e44bca.6d2594","type":"inject","z":"5f1bed63.cb2a94","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.62","x":200,"y":280,"wires":[["98fd0130.0550d"]]},{"id":"98fd0130.0550d","type":"function","z":"5f1bed63.cb2a94","name":"","func":"\nvar m_first = []\nvar m_second = []\nvar a\nvar startTime = 1577836800000\nfor(x=1;x<=25;x++){\n    a = {x: new Date(startTime), y: Math.random() * 300}\n    m_first.push(a)\n    startTime += 86400000\n}\nstartTime = 1577836800000\nfor(x=1;x<=25;x++){\n    a = {x: new Date(startTime), y: -2.5 + Math.random() * 5}\n    m_second.push(a)\n    startTime += 86400000\n}\n\nmsg.payload = {}\nmsg.payload.first = JSON.stringify(m_first)\nmsg.payload.second = JSON.stringify(m_second)\nreturn msg;\n","outputs":1,"noerr":0,"x":340,"y":280,"wires":[["55e9c5a5.e31f0c"]]},{"id":"1f88035e.029a1d","type":"debug","z":"5f1bed63.cb2a94","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":620,"y":320,"wires":[]},{"id":"55e9c5a5.e31f0c","type":"template","z":"5f1bed63.cb2a94","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =300></canvas>\n<script>\nvar textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');\nvar gridcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-groupBorderColor');\nvar linecolors = ['#009900','#889900']\n\nvar ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [\n            {\n                label: 'First',\n                backgroundColor: linecolors[0],\n                borderColor: linecolors[0],\n                data: {{{payload.first}}},\n                yAxisID: 'left-y-axis',\n                steppedLine: true,\n                fill: false,\n                borderWidth: 1\n            },\n            {\n                label: 'Second',\n                backgroundColor: linecolors[1],\n                borderColor: linecolors[1],\n                data: {{{payload.second}}},\n                yAxisID: 'right-y-axis',\n                steppedLine: false,\n                fill: false,\n                borderWidth: 1\n            }\n        ]\n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [\n                {\n                    gridLines :{display:false},\n                    id: 'left-y-axis',\n                    type: 'linear',\n                    position: 'left',\n                    ticks: {\n                        fontColor: linecolors[0]\n                    }\n                },\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    id: 'right-y-axis',\n                    type: 'linear',\n                    position: 'right',\n                    ticks: {\n                        fontColor:linecolors[1]\n                    }\n                }\n            ],\n            xAxes: [\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    type: 'time',\n                    distribution: 'series',\n                    ticks: {\n                        fontColor:textcolor\n                    }\n                }\n            ]\n        }\n    }\n});\n</script>\n","output":"str","x":470,"y":280,"wires":[["26d66b9b.186034","1f88035e.029a1d"]]},{"id":"304730.1de8e8d","type":"ui_group","z":"","name":"Chart","tab":"ebf9c239.14c15","order":3,"disp":true,"width":"15","collapse":false},{"id":"ebf9c239.14c15","type":"ui_tab","z":"","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Or more color coded version (edit - correct colors for dataset)

[{"id":"26d66b9b.186034","type":"ui_template","z":"5f1bed63.cb2a94","group":"304730.1de8e8d","name":"Line Chart","order":4,"width":"15","height":"10","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":640,"y":280,"wires":[[]]},{"id":"29e44bca.6d2594","type":"inject","z":"5f1bed63.cb2a94","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.62","x":200,"y":280,"wires":[["98fd0130.0550d"]]},{"id":"98fd0130.0550d","type":"function","z":"5f1bed63.cb2a94","name":"","func":"\nvar m_first = []\nvar m_second = []\nvar a\nvar startTime = 1577836800000\nfor(x=1;x<=25;x++){\n    a = {x: new Date(startTime), y: Math.random() * 300}\n    m_first.push(a)\n    startTime += 86400000\n}\nstartTime = 1577836800000\nfor(x=1;x<=25;x++){\n    a = {x: new Date(startTime), y: -2.5 + Math.random() * 5}\n    m_second.push(a)\n    startTime += 86400000\n}\n\nmsg.payload = {}\nmsg.payload.first = JSON.stringify(m_first)\nmsg.payload.second = JSON.stringify(m_second)\nreturn msg;\n","outputs":1,"noerr":0,"x":340,"y":280,"wires":[["55e9c5a5.e31f0c"]]},{"id":"1f88035e.029a1d","type":"debug","z":"5f1bed63.cb2a94","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":620,"y":320,"wires":[]},{"id":"55e9c5a5.e31f0c","type":"template","z":"5f1bed63.cb2a94","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =300></canvas>\n<script>\nvar textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');\nvar gridcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-groupBorderColor');\nvar linecolors = ['#009900','#889900']\n\nvar ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [\n            {\n                label: 'First',\n                backgroundColor: linecolors[0],\n                borderColor: linecolors[0],\n                data: {{{payload.first}}},\n                yAxisID: 'left-y-axis',\n                steppedLine: true,\n                fill: false,\n                borderWidth: 1\n            },\n            {\n                label: 'Second',\n                backgroundColor: linecolors[1],\n                borderColor: linecolors[1],\n                data: {{{payload.second}}},\n                yAxisID: 'right-y-axis',\n                steppedLine: false,\n                fill: false,\n                borderWidth: 1\n            }\n        ]\n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [\n                {\n                    gridLines :{display:false},\n                    id: 'left-y-axis',\n                    type: 'linear',\n                    position: 'left',\n                    ticks: {\n                        fontColor: linecolors[0]\n                    }\n                },\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    id: 'right-y-axis',\n                    type: 'linear',\n                    position: 'right',\n                    ticks: {\n                        fontColor:linecolors[1]\n                    }\n                }\n            ],\n            xAxes: [\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    type: 'time',\n                    distribution: 'series',\n                    ticks: {\n                        fontColor:textcolor\n                    }\n                }\n            ]\n        }\n    }\n});\n</script>\n","output":"str","x":470,"y":280,"wires":[["26d66b9b.186034","1f88035e.029a1d"]]},{"id":"304730.1de8e8d","type":"ui_group","z":"","name":"Chart","tab":"ebf9c239.14c15","order":3,"disp":true,"width":"15","collapse":false},{"id":"ebf9c239.14c15","type":"ui_tab","z":"","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

2 Likes

Thanks Buddy! You're awesome!

And here is the basics how to do same thing for live data

[{"id":"26d66b9b.186034","type":"ui_template","z":"5f1bed63.cb2a94","group":"304730.1de8e8d","name":"Line Chart","order":4,"width":"15","height":"10","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":610,"y":270,"wires":[[]]},{"id":"29e44bca.6d2594","type":"inject","z":"5f1bed63.cb2a94","name":"","topic":"","payload":"","payloadType":"date","repeat":"5","crontab":"","once":false,"onceDelay":"0.62","x":250,"y":240,"wires":[["98fd0130.0550d"]]},{"id":"98fd0130.0550d","type":"function","z":"5f1bed63.cb2a94","name":"fake live data","func":"msg.payload = {}\nmsg.payload.first = Math.random() * 300\nmsg.payload.second = -2.5 + Math.random() * 5\nreturn msg;\n","outputs":1,"noerr":0,"x":410,"y":240,"wires":[["26d66b9b.186034"]]},{"id":"55e9c5a5.e31f0c","type":"template","z":"5f1bed63.cb2a94","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =300></canvas>\n<script>\nvar textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');\nvar gridcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-groupBorderColor');\nvar linecolors = ['#009900','#889900']\nvar maxDataPoints = 20\n\nvar ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [\n            {\n                label: 'first',\n                backgroundColor: linecolors[0],\n                borderColor: linecolors[0],\n                data: [],\n                yAxisID: 'left-y-axis',\n                steppedLine: true,\n                fill: false,\n                borderWidth: 1\n            },\n            {\n                label: 'second',\n                backgroundColor: linecolors[1],\n                borderColor: linecolors[1],\n                data: [],\n                yAxisID: 'right-y-axis',\n                steppedLine: false,\n                fill: false,\n                borderWidth: 1\n            }\n        ]\n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [\n                {\n                    gridLines :{display:false},\n                    id: 'left-y-axis',\n                    type: 'linear',\n                    position: 'left',\n                    ticks: {\n                        fontColor: linecolors[0]\n                    }\n                },\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    id: 'right-y-axis',\n                    type: 'linear',\n                    position: 'right',\n                    ticks: {\n                        fontColor:linecolors[1]\n                    }\n                }\n            ],\n            xAxes: [\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    type: 'time',\n                    distribution: 'series',\n                    time:{\n                        displayFormats: {\n                            quarter: 'MMM YYYY',\n                            millisecond:'h:mm:ss',\n                            second:\t'h:mm:ss',\n                            minute:\t'h:mm',\n                            hour:\t'h'                        \n                        }\n                    },\n                    \n                    ticks: {\n                        fontColor:textcolor\n                    }\n                }\n            ]\n        }\n    }\n});\nfunction addData(chart, data, label) {\n    chart.data.datasets.forEach((dataset) => {\n        if(dataset.label == label){\n            dataset.data.push(data);\n        }\n        if(dataset.data.length > maxDataPoints){\n            dataset.data.shift()\n        }\n    });\n    chart.update(0);//0 means no animation\n}\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    if (msg) {\n      // Do something when msg arrives\n      addData(chart,{x:new Date(),y:msg.payload.first},\"first\")\n      addData(chart,{x:new Date(),y:msg.payload.second},\"second\")\n\n    }\n  });\n})(scope);\n</script>\n","output":"str","x":400,"y":300,"wires":[["26d66b9b.186034"]]},{"id":"bf7ecf9e.8f61f","type":"inject","z":"5f1bed63.cb2a94","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":250,"y":300,"wires":[["55e9c5a5.e31f0c"]]},{"id":"304730.1de8e8d","type":"ui_group","z":"","name":"Chart","tab":"ebf9c239.14c15","order":3,"disp":true,"width":"15","collapse":false},{"id":"ebf9c239.14c15","type":"ui_tab","z":"","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

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

The live data example works well, but I've been unable to persist the chart between browser sessions. The data that I'm processing spans 24hrs, and currently it's only plotted whilst the browser is open.
My idea was trying to continually export the dataset.data, save it to file context, then on a new browser session restore that data back into the chart, but it hasn't really worked out :confused:
Are there any thoughts how this can be achieved?

EDIT - Should I build, save & limit the data object external to the template node (instead of building it in the browser), and then push the entire objects into the respective dataset.data, so the chart is redrawn every time the flow is run.

I can't see any other options. If there is no browser session, the data must be still be available for next session. But after the dashboard connected and chunk of data feed to the chart, it is reasonable to update again as live chart, adding every single data-point. Heavy chunks of data over socket just don't do any good so you can keep it low that way.
According to this example flow, it misses the option of updating with chunk of data, but it is not too complicated thing to add.
Also the limitation by count should be changed to filter out data older than you'll need.

1 Like

I've built the chunk of data in a function node and saved it to context (keeping the arrays to a preset length).
On a browser connect, the context 'chunk data' is injected into the template node using the msg.topic - "restore".
In the template node, I am distinguishing the 'live data' from the 'chunk data' .

(function(scope) {
  scope.$watch('msg', function(msg) {
    //check if msg is 'live' or 'restore'
    if (msg.topic=="restore") {
      //do something to restore data
    } else if (msg) {
      // update live data
      addData(chart,{x:new Date(),y:msg.payload.first},"first")
      addData(chart,{x:new Date(),y:msg.payload.second},"second")
    }
  });

...and there I have come to a halt, because although the 'context chunk data' is formatted as per your earlier example, I don't know how to use it in the template.
Any ideas please?

linechart

[{"id":"8496abf.bdd4b58","type":"ui_template","z":"c4396940.2c4cc8","group":"6d56c1dd.99aa2","name":"Line Chart","order":4,"width":"15","height":"10","format":"","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":570,"y":1000,"wires":[[]]},{"id":"e91eab68.64fd68","type":"template","z":"c4396940.2c4cc8","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =300></canvas>\n<script>\nvar textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');\nvar gridcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-groupBorderColor');\nvar linecolors = ['#5d60ff','#ff5d5d']\nvar maxDataPoints = 20\n\nvar ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [\n            {\n                label: 'first',\n                backgroundColor: linecolors[0],\n                borderColor: linecolors[0],\n                data: [],\n                yAxisID: 'left-y-axis',\n                steppedLine: false,\n                fill: false,\n                borderWidth: 1\n            },\n            {\n                label: 'second',\n                backgroundColor: linecolors[1],\n                borderColor: linecolors[1],\n                data: [],\n                yAxisID: 'right-y-axis',\n                steppedLine: false,\n                fill: true,\n                borderWidth: 1\n            }\n        ]\n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [\n                {\n                    gridLines :{display:false},\n                    id: 'left-y-axis',\n                    type: 'linear',\n                    position: 'left',\n                    ticks: {\n                        fontColor: linecolors[0]\n                    }\n                },\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    id: 'right-y-axis',\n                    type: 'linear',\n                    position: 'right',\n                    ticks: {\n                        fontColor:linecolors[1]\n                    }\n                }\n            ],\n            xAxes: [\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    type: 'time',\n                    distribution: 'series',\n                    time:{\n                        displayFormats: {\n                            quarter: 'MMM YYYY',\n                            millisecond:'h:mm:ss',\n                            second:\t'h:mm:ss',\n                            minute:\t'h:mm',\n                            hour:\t'h'                        \n                        }\n                    },\n                    \n                    ticks: {\n                        fontColor:textcolor\n                    }\n                }\n            ]\n        }\n    }\n});\nfunction addData(chart, data, label) {\n    chart.data.datasets.forEach((dataset) => {\n        if(dataset.label == label){\n            dataset.data.push(data);\n        }\n        if(dataset.data.length > maxDataPoints){\n            dataset.data.shift()\n        }\n    });\n    chart.update(0);//0 means no animation\n}\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    //check if msg is 'live' or 'restore'\n    if (msg.topic==\"restore\") {\n      //do something to restore data\n    } else if (msg) {\n      // update live data\n      addData(chart,{x:new Date(),y:msg.payload.first},\"first\")\n      addData(chart,{x:new Date(),y:msg.payload.second},\"second\")\n    }\n  });\n})(scope);\n</script>\n","output":"str","x":380,"y":960,"wires":[["8496abf.bdd4b58"]]},{"id":"6d48838f.c861ac","type":"inject","z":"c4396940.2c4cc8","name":"Initialize","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":960,"wires":[["e91eab68.64fd68"]]},{"id":"15644e1e.7c2ab2","type":"inject","z":"c4396940.2c4cc8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":"0.62","topic":"","payload":"","payloadType":"date","x":115,"y":1040,"wires":[["c3575dfd.f6964"]],"l":false},{"id":"c3575dfd.f6964","type":"function","z":"c4396940.2c4cc8","name":"fake live data","func":"msg.payload = {}\nmsg.payload.first = Math.round(Math.random() * 100)\nmsg.payload.second = Math.round(Math.random() * 100)\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":230,"y":1040,"wires":[["2ce6466a.38212a"]]},{"id":"2ce6466a.38212a","type":"function","z":"c4396940.2c4cc8","name":"Config","func":"var data1 = msg.payload.first\nvar data2 = msg.payload.second\nvar maxData = 20\n\nvar m_first = flow.get(\"chartdata.first\")||[]\nvar m_second = flow.get(\"chartdata.second\")||[]\n\nvar a\nvar timeStamp = new Date()\n\n    a = {x: timeStamp, y: data1}\n    m_first.push(a)\n    if (m_first.length > maxData){m_first.shift()}\n\n    a = {x: timeStamp, y: data2}\n    m_second.push(a)\n    if (m_second.length > maxData){m_second.shift()}\n\nlet savedD = {}\nsavedD.first = (m_first)\nsavedD.second = (m_second)\nflow.set(\"chartdata\", savedD);\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":390,"y":1040,"wires":[["8496abf.bdd4b58"]]},{"id":"68f0956f.f388ec","type":"change","z":"c4396940.2c4cc8","name":"Restore data","rules":[{"t":"set","p":"chartdata","pt":"msg","to":"chartdata","tot":"flow"},{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.first","pt":"msg","to":"$string(chartdata.first)","tot":"jsonata"},{"t":"set","p":"payload.second","pt":"msg","to":"$string(chartdata.second)","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"restore","tot":"str"},{"t":"delete","p":"chartdata","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":1000,"wires":[["8496abf.bdd4b58"]]},{"id":"63e9f633.a79e08","type":"ui_ui_control","z":"c4396940.2c4cc8","name":"","events":"connect","x":140,"y":1000,"wires":[["68f0956f.f388ec"]]},{"id":"6d56c1dd.99aa2","type":"ui_group","z":"","name":"Chart","tab":"b7b17e22.6df42","order":3,"disp":true,"width":"15","collapse":false},{"id":"b7b17e22.6df42","type":"ui_tab","z":"","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

Made a little changes (with comments inside)

[{"id":"8496abf.bdd4b58","type":"ui_template","z":"63163740.2d4508","group":"6d56c1dd.99aa2","name":"Line Chart","order":4,"width":"15","height":"10","format":"","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":710,"y":280,"wires":[[]]},{"id":"e91eab68.64fd68","type":"template","z":"63163740.2d4508","name":"","field":"template","fieldType":"msg","format":"html","syntax":"mustache","template":"<canvas id=\"myChart\" width=600 height =300></canvas>\n<script>\nvar textcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-widgetTextColor');\nvar gridcolor = getComputedStyle(document.documentElement).getPropertyValue('--nr-dashboard-groupBorderColor');\nvar linecolors = ['#5d60ff','#ff5d5d']\n\nvar ctx = document.getElementById('myChart').getContext('2d');\nvar chart = new Chart(ctx, {\n    // The type of chart we want to create\n    type: 'line',\n\n    // The data for our dataset\n    data: {\n        labels: [],\n        datasets: [\n            {\n                label: 'first',\n                backgroundColor: linecolors[0],\n                borderColor: linecolors[0],\n                data: [],\n                yAxisID: 'left-y-axis',\n                steppedLine: false,\n                fill: false,\n                borderWidth: 1\n            },\n            {\n                label: 'second',\n                backgroundColor: linecolors[1],\n                borderColor: linecolors[1],\n                data: [],\n                yAxisID: 'right-y-axis',\n                steppedLine: false,\n                fill: true,\n                borderWidth: 1\n            }\n        ]\n    },\n\n    // Configuration options go here\n    options: {\n        scales: {\n            yAxes: [\n                {\n                    gridLines :{display:false},\n                    id: 'left-y-axis',\n                    type: 'linear',\n                    position: 'left',\n                    ticks: {\n                        fontColor: linecolors[0]\n                    }\n                },\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    id: 'right-y-axis',\n                    type: 'linear',\n                    position: 'right',\n                    ticks: {\n                        fontColor:linecolors[1]\n                    }\n                }\n            ],\n            xAxes: [\n                {\n                    gridLines :{zeroLineColor:gridcolor,color:gridcolor,lineWidth:0.5},\n                    type: 'time',\n                    distribution: 'series',\n                    time:{\n                        displayFormats: {\n                            quarter: 'MMM YYYY',\n                            millisecond:'h:mm:ss',\n                            second:\t'h:mm:ss',\n                            minute:\t'h:mm',\n                            hour:\t'h'                        \n                        }\n                    },\n                    \n                    ticks: {\n                        fontColor:textcolor\n                    }\n                }\n            ]\n        }\n    }\n});\nfunction addData(chart, data, label) {\n    // same calculation as for data storage at server side\n    // data.x is newest data so treated as now.\n    var old = data.x - 1000 * 60 * 2 \n    \n    chart.data.datasets.forEach((dataset) => {\n        if(dataset.label == label){\n            dataset.data.push(data);\n        }\n        dataset.data = dataset.data.filter(entry => entry.x > old)// filter out old data.\n        \n    });\n    chart.update(0);//0 means no animation\n}\nfunction restoreChart(chart, data) {\n    // overwrite datasets (but not clear all)\n    // based on incoming data\n    // if chart has datasets which then not found from icoming data, those remain\n    var dataset\n    Object.keys(data).forEach(label => {\n        dataset = chart.data.datasets.find(ds => {return ds.label === label })// find corresponding dataset\n        if(dataset){\n            dataset.data = data[label]// if found, replace with incoming data for that dataset\n        }\n    })\n    chart.update(0);//0 means no animation\n}\n(function(scope) {\n    scope.$watch('msg', function(msg) {\n        if(msg) {\n            if (msg.topic == \"restore\") {\n                // restore chart\n                restoreChart(chart, msg.payload)\n            }\n            else{\n                //add datapoints one by one\n                addData(chart, msg.payload, msg.topic)\n            }\n        }\n   \n  });\n})(scope);\n</script>\n","output":"str","x":520,"y":240,"wires":[["8496abf.bdd4b58"]]},{"id":"6d48838f.c861ac","type":"inject","z":"63163740.2d4508","name":"Initialize","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":240,"wires":[["e91eab68.64fd68"]]},{"id":"15644e1e.7c2ab2","type":"inject","z":"63163740.2d4508","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":false,"onceDelay":"0.62","topic":"","payload":"","payloadType":"date","x":215,"y":340,"wires":[["c3575dfd.f6964","6dd9fa64.0ebb74"]],"l":false},{"id":"c3575dfd.f6964","type":"function","z":"63163740.2d4508","name":"fake first data","func":"msg.payload = Math.round(Math.random() * 100)\nmsg.topic = 'first'\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":320,"wires":[["1735652c.72d0ab"]]},{"id":"63e9f633.a79e08","type":"ui_ui_control","z":"63163740.2d4508","name":"","events":"connect","x":200,"y":280,"wires":[["d4de9d72.8ce92"]]},{"id":"6dd9fa64.0ebb74","type":"function","z":"63163740.2d4508","name":"fake second data","func":"msg.payload = Math.round(Math.random() * 100)\nmsg.topic = 'second'\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":360,"wires":[["1735652c.72d0ab"]]},{"id":"1735652c.72d0ab","type":"function","z":"63163740.2d4508","name":"store","func":"var storage = flow.get('chartData') || {first:[],second:[]} // data structure to match the chart datasets\n\nvar now = new Date().getTime() // the moment of datapoint creation\nvar old = now - 1000 * 60 * 2  // too old data will be 2 minutes\nvar datapoint = {x:now, y:msg.payload} // create the datapoint\n\nstorage[msg.topic].push(datapoint) // push datapoint into correct object's array in storage\n\nstorage[msg.topic] = storage[msg.topic].filter(entry => entry.x > old)// filter out any too old data\n\nflow.set('chartData',storage)// write storage to flow context\n\nmsg.payload = datapoint // send out the created datapoint (msg.topic remains same)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":340,"wires":[["8496abf.bdd4b58"]]},{"id":"99d40b3b.6ca708","type":"change","z":"63163740.2d4508","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"chartData","tot":"flow"},{"t":"set","p":"topic","pt":"msg","to":"restore","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":280,"wires":[["8496abf.bdd4b58"]]},{"id":"d4de9d72.8ce92","type":"switch","z":"63163740.2d4508","name":"","property":"chartData","propertyType":"flow","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":350,"y":280,"wires":[["99d40b3b.6ca708"]]},{"id":"6d56c1dd.99aa2","type":"ui_group","name":"Chart","tab":"b7b17e22.6df42","order":3,"disp":true,"width":"15","collapse":false},{"id":"b7b17e22.6df42","type":"ui_tab","name":"Ovens","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
1 Like

Thanks @hotNipi, your version works well, and data is now restored as soon as a browser connects.

It's amazing how many different options can be used in chartjs - different line styles, gradients, fills... the list is exhaustive!!

Beautiful world behind the curtains ... :slight_smile:

2 Likes