Problems displaying live data in template with chartjs

I am trying to create a graph with 3 y axis using the ui-template of flowfuse but I have problems setting the data points.

Here is the logic:

[
    {
        "id": "92fb440a9871ab5d",
        "type": "catch",
        "z": "1c6c6bc511cd2d54",
        "name": "",
        "scope": null,
        "uncaught": false,
        "x": 760,
        "y": 300,
        "wires": [
            [
                "0783d5e36455cc58"
            ]
        ]
    },
    {
        "id": "0783d5e36455cc58",
        "type": "debug",
        "z": "1c6c6bc511cd2d54",
        "name": "debug 3",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 940,
        "y": 300,
        "wires": []
    },
    {
        "id": "9e5f9bdc599c2bfa",
        "type": "complete",
        "z": "1c6c6bc511cd2d54",
        "name": "",
        "scope": [
            "8dccb30859665dd9"
        ],
        "uncaught": false,
        "x": 770,
        "y": 360,
        "wires": [
            [
                "7cf07454f7ab4928"
            ]
        ]
    },
    {
        "id": "7cf07454f7ab4928",
        "type": "debug",
        "z": "1c6c6bc511cd2d54",
        "name": "debug 5",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 940,
        "y": 360,
        "wires": []
    },
    {
        "id": "13466bf49075c9dd",
        "type": "ui-template",
        "z": "1c6c6bc511cd2d54",
        "group": "459ee3e2b7fa9235",
        "page": "",
        "ui": "",
        "name": "Klimawerte",
        "order": 1,
        "width": "5",
        "height": "4",
        "head": "",
        "format": "<template>\n    <canvas ref=\"chart\" />\n</template>\n\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script>\n\n<script>\n    export default {\n        mounted() {\n            // register a listener for incoming data\n            this.$socket.on('msg-input:' + this.id, this.onInput)\n\n            // code here when the component is first loaded\n            let interval = setInterval(() => {\n                if (window.Chart) {\n                    // Babylon.js is loaded, so we can now use it\n                    clearInterval(interval);\n                    this.draw()\n                }\n            }, 100);\n        },\n        methods: {\n            onInput (msg) {\n                // add a new data point ot our existing dataset\n                // add time labels as array\n                // add 3 series data as array\n                //Array1.splice(0, Array1.length, ...Array2);\n                this.chart.data.datasets[0].data.length = 0\n                this.chart.data.datasets[0].data.push(msg.payload.CO2_series)\n                this.chart.data.datasets[1].data.length = 0\n                this.chart.data.datasets[1].data.push(msg.payload.Temp_series)\n                this.chart.data.datasets[2].data.length = 0\n                this.chart.data.datasets[2].data.push(msg.payload.RH_series)\n                this.chart.data.labels.length = 0;\n                this.chart.data.labels.push(msg.payload.TimeLabels)\n                // ensure the chart re-renders\n                this.chart.update()\n            },\n            draw () {\n                const ctx = this.$refs.chart\n                new Chart(ctx, {\n                    type: 'line',\n                    data: {\n                        labels: [1767079800000],\n                        datasets: [\n                            {\n                            label: 'CO2',\n                            borderColor: 'red',\n                            data: [500],\n                            yAxisID: 'y',\n                            pointStyle: false,\n                            },\n                            {\n                            label: 'Temperature',\n                            borderColor: '#7CBB00',\n                            data: [20],\n                            yAxisID: 'y1',\n                            pointStyle: false,\n                            },\n                            {\n                            label: 'RH',\n                            borderColor: '#2800bbff',\n                            backgroundColor: '#2800bbff',\n                            data: [80],\n                            yAxisID: 'y2',\n                            pointStyle: false,\n                            },\n                        ],\n                    },\n                    options: {\n                        responsive: true,\n                        maintainAspectRatio: false,\n                        stacked: false,\n                        title: {\n                        display: true,\n                        },\n                        scales: {\n                            x: {\n                                title:{\n                                    display: true,\n                                    text: \"Datum\",\n                                },\n                            },\n                            y: {\n                                title: {\n                                    display: true,\n                                    text: 'CO2 (ppm)',\n                                    color: '#f87979',\n                                },\n                                position: 'left',\n                                max: 2000,\n                                min: 0,\n                                ticks: {\n                                stepSize: 500,\n                                fontColor: 'red',\n                                color: '#f87979',\n                                },\n                            },\n                            y1: {\n                                title: {\n                                display: true,\n                                text: 'Temperature (°C)',\n                                color: '#7CBB00',\n                                },\n                                position: 'right',\n                                max: 25,\n                                min: 15,\n                                grid: {\n                                    drawOnChartArea: false,\n                                },\n                            },\n                            y2: {\n                                title: {\n                                display: true,\n                                text: 'Relative Humidity (%)',\n                                color: '#2800bbff',\n                                },\n                                position: 'right',\n                                max: 100,\n                                min: 30,\n                                grid: {\n                                    drawOnChartArea: false,\n                                },\n                            },\n                        },\n                    }\n                });\n            }\n        }\n    }\n</script>",
        "storeOutMessages": true,
        "passthru": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 730,
        "y": 220,
        "wires": [
            []
        ]
    },
    {
        "id": "ab7f34a950855549",
        "type": "debug",
        "z": "1c6c6bc511cd2d54",
        "name": "debug 6",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 640,
        "y": 400,
        "wires": []
    },
    {
        "id": "beeca0f426bc173c",
        "type": "function",
        "z": "1c6c6bc511cd2d54",
        "name": "function 1",
        "func": "var obj = {};\nobj.RH_series=[]\nobj.Temp_series=[]\nobj.CO2_series=[] \nobj.TimeLabels=[];\nvar element;\nfor (const [index, el] of msg.payload.entries()) {\n    obj.RH_series.push(el.RH);\n    obj.CO2_series.push(el.CO2);\n    obj.Temp_series.push(el.Temp);\n    obj.TimeLabels.push(new Date(el._time).getTime())\n  if ( index === 5 ) break;\n}\n//    temp.push(element.temp);\n//    ppm.push(element.ppm)\n    //labels.push(new Date(element._time).getTime())\n\nmsg.payload = obj;\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 500,
        "y": 280,
        "wires": [
            [
                "ab7f34a950855549",
                "13466bf49075c9dd"
            ]
        ]
    },
    {
        "id": "459ee3e2b7fa9235",
        "type": "ui-group",
        "name": "Gruppe 1",
        "page": "b1366025f77b8dd4",
        "width": 6,
        "height": 1,
        "order": 1,
        "showTitle": true,
        "className": "",
        "visible": true,
        "disabled": false,
        "groupType": "default"
    },
    {
        "id": "b1366025f77b8dd4",
        "type": "ui-page",
        "name": "Seite 1",
        "ui": "6a50f35f2ffe099b",
        "path": "/page1",
        "icon": "home",
        "layout": "grid",
        "theme": "dfda5a006f3f7e59",
        "breakpoints": [
            {
                "name": "Default",
                "px": 0,
                "cols": 3
            },
            {
                "name": "Tablet",
                "px": 576,
                "cols": 6
            },
            {
                "name": "Small Desktop",
                "px": 768,
                "cols": 9
            },
            {
                "name": "Desktop",
                "px": 1024,
                "cols": 12
            }
        ],
        "order": 1,
        "className": "",
        "visible": "true",
        "disabled": "false"
    },
    {
        "id": "6a50f35f2ffe099b",
        "type": "ui-base",
        "name": "Mein Dashboard",
        "path": "/dashboard",
        "appIcon": "",
        "includeClientData": true,
        "acceptsClientConfig": [
            "ui-notification",
            "ui-control"
        ],
        "showPathInSidebar": false,
        "headerContent": "page",
        "navigationStyle": "default",
        "titleBarStyle": "default",
        "showReconnectNotification": true,
        "notificationDisplayTime": 1,
        "showDisconnectNotification": true,
        "allowInstall": false
    },
    {
        "id": "dfda5a006f3f7e59",
        "type": "ui-theme",
        "name": "Standardthema",
        "colors": {
            "surface": "#ffffff",
            "primary": "#0094CE",
            "bgPage": "#eeeeee",
            "groupBg": "#ffffff",
            "groupOutline": "#cccccc"
        },
        "sizes": {
            "density": "default",
            "pagePadding": "12px",
            "groupGap": "12px",
            "groupBorderRadius": "4px",
            "widgetGap": "12px"
        }
    },
    {
        "id": "3fb11335f58241f8",
        "type": "global-config",
        "env": [],
        "modules": {
            "@flowfuse/node-red-dashboard": "1.30.0"
        }
    }
]

My object that is coming in looks like this:

So each of the 3 axis has a number array with values.
I assign the values in the ui-template like so:

But what i get is only the chart without any lines.

The one point that is showing is hardcoded in the chart.config and should be replaced by the new incoming data.

Apart from that, as soon as I set the xAxis to "type = 'time'" nothing is displayed any more. I know that in vue I have to import a date adapter for the time series to work, but I assume that this is already imported in node red dashboard?

Any help much appreciated!

Welcome to the forum @joachim_bl

Please select the template node and Export it to the clipboard and paste it in here. Then we will be able to see exactly what you have done. You have not even told us which chart library you are using.

In order to make the flow readable and usable it is necessary to surround it with three backticks (also known as a left quote or backquote ```)

``` 
   code goes here 
```

See this post for more details - How to share code or flow json

Hi Colin, i have added the flow. I use chartjs.

In that case I can't help, you will need someone who knows about chartjs. The dashboard uses eCharts for its builtin charts.

It might be a good idea to edit the post title so that it is clear that you are using chartjs in the template.

I thought chartjs was the chart control behind the chart node. But obviously they have changed that. It is very difficult for a newcomer to get on the right track with all these "old" examples around. I might just try to do it in echart if that is now the standard.

You might get some clues from this post from @Buckskin.

He has multiple y axes and draws at least one line.

Yes, i have seen this and even tried (it is echart), but I only see the headline, the chart area is empty and errors show up in the console:

I wish i had a simple working example of a customized echart, but until now i couldn´t find any.

Hmm that example does work for me - as you say I see only the title, but injecting the test data shows the chart.

Once something has gone wrong with a chart, it seems impossible to recover.
Try clearing your browser cache and restarting Node-red.
Also worth updating @flowfuse/node-red-dashboard, a new bugfix release was published today.

I do find it a bit odd that msg.payload is injected as a Jsonata expression. I think it should be json, and amazingly, the chart works either way.

Yes indeed!

Have you tried the provided demo in the docs: Template ui-template | Node-RED Dashboard 2.0

chrome_zSQj3fM5LS

I use the weather forecast eChart so I know it works. This is some test data to give you an idea of how the data is formatted. (sorry the inject node with it was too big to post)

{
   "temperature":[
       11.45,
       9.51,
       7.97,
       6.83,
       6.18,
       5.17,
       4.33,
       4.67,
       4.62,
       5.75,
       5.87,
       6.61,
       7.12,
       8.7,
       9.79,
       10.93,
       11.56,
       11.65,
       12.2,
       12.02,
       12.29,
       12.19,
       12.13,
       11.72
   ],
   "precipitation":[
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       6,
       2,
       0,
       0,
       0,
       0.5,
       0,
       2.4,
       0,
       0,
       0,
       0
   ],
   "windSpeed":[
       4.49,
       3.18,
       2.99,
       2.33,
       2.09,
       1.47,
       0.7,
       0.57,
       0.6,
       0.89,
       1.35,
       1.22,
       1.42,
       2.27,
       1.99,
       2.52,
       3.57,
       4.35,
       4.71,
       4.67,
       4.73,
       4.48,
       4.74,
       3.81
   ],
   "labels":[
       "19:00",
       "20:00",
       "21:00",
       "22:00",
       "23:00",
       "00:00",
       "01:00",
       "02:00",
       "03:00",
       "04:00",
       "05:00",
       "06:00",
       "07:00",
       "08:00",
       "09:00",
       "10:00",
       "11:00",
       "12:00",
       "13:00",
       "14:00",
       "15:00",
       "16:00",
       "17:00",
       "18:00"
   ],
   "iconline":[
       {
           "line":15.45,
           "iconNumber":1,
           "iconDescription":"Sunny Day"
       },
       {
           "line":13.51,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":11.97,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":10.83,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":10.18,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":9.17,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":8.33,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":8.67,
           "iconNumber":0,
           "iconDescription":"Clear Night"
       },
       {
           "line":8.62,
           "iconNumber":2,
           "iconDescription":"Partly Cloudy (Night)"
       },
       {
           "line":9.75,
           "iconNumber":2,
           "iconDescription":"Partly Cloudy (Night)"
       },
       {
           "line":9.87,
           "iconNumber":2,
           "iconDescription":"Partly Cloudy (Night)"
       },
       {
           "line":10.61,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":11.12,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":12.7,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":13.79,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":14.93,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":15.56,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":15.65,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":16.2,
           "iconNumber":8,
           "iconDescription":"Overcast"
       },
       {
           "line":16.02,
           "iconNumber":7,
           "iconDescription":"Cloudy"
       },
       {
           "line":16.29,
           "iconNumber":8,
           "iconDescription":"Overcast"
       },
       {
           "line":16.19,
           "iconNumber":8,
           "iconDescription":"Overcast"
       },
       {
           "line":16.13,
           "iconNumber":8,
           "iconDescription":"Overcast"
       },
       {
           "line":15.72,
           "iconNumber":8,
           "iconDescription":"Overcast"
       }
   ],
   "forecastLocation":"Slockavullin",
   "runDate":"21/09/2025, 18:00:00"
}

One thing to note is that if you have chart.js nodes on a dashboard the eChart.js charts may not show any data. I have no idea why but I had to swap ALL my chart.js template charts before the eChart versions would work reliably.

Thanks for the link. I had not seen that.

@Buckskin, can you share the code to transform data from the Met Office into that format?

Here is what I use, but I am pretty certain that I got the original from a post by, possibly, yourself (certainly from someone who posted a complete weather forecast page). I liked the chart that was included so messed about until I got a reasonable copy in Dashboard 2.

I haven't looked at the code etc. for a while so I am sure it can be improved.

The Met Office API I use is "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/hourly?dataSource=BD1". I mention this because they seem to have bunches of APIs

[{"id":"163e492e0f2a4817","type":"function","z":"9fb2acebd1bf944c","name":"Met Office \\n Data Capture","func":"/** Interpret & enhance the UK Met Office \"Site Specific\" forecast data\n * Save to global `metOfficeWeather` variable and output to MQTT.\n * \n * Note that the free API license only allows 360 calls per day so we only\n * run this from 5am to midnight hourly.\n * \n */\n\n/**\n * \n * Input\n * mag.payload  {Object}  {\n *                        features: [\n *                                  {type: feature,\n *                                   geometry: {},\n *                                   properties: {\n *                                      location: {},\n *                                        requestPointDistance: <number>,\n *                                        modelRunDate: <date string>,\n *                                        timeSeries: [\n *                                                      {time: <date string>,\n *                                                       screenTemperature: <number>,                         Screen Air Temperature\n *                                                       maxScreenAirTemp: <number>,                          Maximum Screen Air Temperature Over Previous Hour\n *                                                       minScreenAirTemp: <number>,                          Minimum Screen Air Temperature Over Previous Hour\n *                                                       screenDewPointTemperature: <number>,                 Screen Dew Point Temperature\n *                                                       feelsLikeTemperature: <number>,                      Feels Like Temperature\n *                                                       windSpeed10m: <number>,                              10m Wind Speed\n *                                                       windDirectionFrom10m: <number>,                      10m Wind From Direction\n *                                                       windGustSpeed10m: <number>,                          10m Wind Gust Speed\n *                                                       max10mWindGust: <number>,                            Maximum 10m Wind Gust Speed Over Previous Hour\n *                                                       visibility: <number>,                                Visibility\n *                                                       screenRelativeHumidity: <number>,                    Screen Relative Humidity\"\n *                                                       mslp: <number>,                                      Mean Sea Level Pressure\n *                                                       uvIndex: <number>,                                   UV Index\n *                                                       significantWeatherCode: <number>,                    The relevant Met Office weather icon\n *                                                       precipitationRate: <number>,                         Precipitation Rate\n *                                                       totalPrecipAmount: <number>,                         Total Precipitation Amount Over Previous Hour\n *                                                       totalSnowAmount: <number>                            Total Snow Amount Over Previous Hour\n *                                                       probOfPrecipitation: <number>,                       Probability of Precipitation\n *                                                      },\n *                                                      {...} etc\n *                                                    ]\n *                                    },\n *                                    ],\n *                      parameters: [],\n *                      }\n * \n */\n\n// Quick exit if no data\nif (!Object.hasOwn(msg.payload, 'features')) {\n  return\n  \n}\n\n// Save a copy of the API so we don't have to keep re-running for testing\nflow.set('metofficeapiout', msg.payload)\n\n// Get data for next 2 days at hourly intervals\nconst weatherData = msg.payload.features[0].properties.timeSeries\nconst forecastWeatherData = []\n\nconst metIcons = context.get('metIcons')                                            // See 'On Start' for creation of these\nconst metOfficeWeather = global.get('metOfficeWeather', 'file') ?? {}\n\nconst currentTime = new Date()\nconst currentMillis = currentTime.getTime()\n\nlet closestTimeIndex = 0\nlet closestTimeDifference = Infinity\n\n// Enhance and normalise data\nfor (let i = 0; i < weatherData.length; i++) {\n  forecastWeatherData[i] = {}\n\n  const dataTime = new Date(weatherData[i].time)\n  const dataMillis = dataTime.getTime()\n  const timeDifference = Math.abs(currentMillis - dataMillis)                       // Time difference between now and first entry in Met Office weather data\n\n  // More sensible names\n  forecastWeatherData[i].time = weatherData[i].time\n  forecastWeatherData[i].temperature = weatherData[i].screenTemperature\n  forecastWeatherData[i].humidity = weatherData[i].screenRelativeHumidity\n  forecastWeatherData[i].precipitation =  weatherData[i].totalPrecipAmount ?? 0     // Sometimes there is no precipitation entry\n  forecastWeatherData[i].windSpeed =  weatherData[i].windSpeed10m\n\n  // Icon and description\n  const icon = metIcons[weatherData[i].significantWeatherCode]\n  forecastWeatherData[i].icon = weatherData[i].significantWeatherCode\n  forecastWeatherData[i].description = icon.text\n  weatherData[i].description = icon.text\n  \n  // Is the barometer rising or falling?\n  if (i < (weatherData.length - 1)) {\n    if (weatherData[i].mslp < weatherData[i + 1].mslp) forecastWeatherData[i].barometerChange = 'rising'\n\n    else if (weatherData[i].mslp > weatherData[i + 1].mslp) forecastWeatherData[i].barometerChange = 'falling'\n\n    else forecastWeatherData[i].barometerChange = 'steady'\n\n  } else {\n    forecastWeatherData[i].barometerChange = 'NA'\n\n  }\n\n  // Work out which entry is closest to now so we can record \"current\" forecast\n  if (currentTime.getHours() === dataTime.getHours() && closestTimeIndex === 0) {\n    closestTimeDifference = timeDifference\n    closestTimeIndex = i\n  \n  }\n\n}\n\n// Save the data to context\nmetOfficeWeather.forecast = weatherData\n\n// What does the data mean?\nmetOfficeWeather.schema = msg.payload.parameters[0]\n\n// Where is the forecast actually for and how far away is that?\nmetOfficeWeather.location = {\n  place: msg.payload.features[0].properties.location.name,\n  distance: msg.payload.features[0].properties.requestPointDistance,\n  coordinates: msg.payload.features[0].geometry.coordinates,\n}\n\n// When was the forecast updated?\nmetOfficeWeather.modelRunDate = msg.payload.features[0].properties.modelRunDate\n\nflow.set('metOfficeWeather', metOfficeWeather, 'file')\n\n// Output the current forecast\nreturn {\n  topic: 'Met Office Current Weather Forecast',\n  payload: {data: forecastWeatherData, location: metOfficeWeather.location, runDate: metOfficeWeather.modelRunDate},\n  currentForecast: weatherData[closestTimeIndex],\n\n}\n\n\n\n/*\nhttps://datahub.metoffice.gov.uk/docs/f/category/site-specific/overview\n{\n  \"time\":\"2024-04-14T15:00Z\",\n  \"screenTemperature\":11.35,\n  \"maxScreenAirTemp\":11.81,\n  \"minScreenAirTemp\":11,\n  \"screenDewPointTemperature\":1.26,\n  \"feelsLikeTemperature\":8.61,\n  \"windSpeed10m\":6.03,\n  \"windDirectionFrom10m\":252,\n  \"windGustSpeed10m\":10.36,\n  \"max10mWindGust\":10.36,\n  \"visibility\":28666,\n  \"screenRelativeHumidity\":49.3,\n  \"mslp\":101913,\"uvIndex\":2,\n  \"significantWeatherCode\":3,\n  \"precipitationRate\":0,\n  \"totalPrecipAmount\":0,\n  \"totalSnowAmount\":0,\n  \"probOfPrecipitation\":2\n}\n*/","outputs":1,"timeout":0,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\n/**\n * 0   Clear night\n * 1\tSunny day\n * 2\tPartly cloudy (night)\n * 3\tPartly cloudy (day)\n * 4\tNot used\n * 5\tMist\n * 6\tFog\n * 7\tCloudy\n * 8\tOvercast\n * 9\tLight rain shower (night)\n * 10\tLight rain shower (day)\n * 11\tDrizzle\n * 12\tLight rain\n * 13\tHeavy rain shower (night)\n * 14\tHeavy rain shower (day)\n * 15\tHeavy rain\n * 16\tSleet shower (night)\n * 17\tSleet shower (day)\n * 18\tSleet\n * 19\tHail shower (night)\n * 20\tHail shower (day)\n * 21\tHail\n * 22\tLight snow shower (night)\n * 23\tLight snow shower (day)\n * 24\tLight snow\n * 25\tHeavy snow shower (night)\n * 26\tHeavy snow shower (day)\n * 27\tHeavy snow\n * 28\tThunder shower (night)\n * 29\tThunder shower (day)\n * 30\tThunder\n */\n\ncontext.set('metIcons', {\n    0: { \"icon\": \"\\uE594\", \"text\": \"Clear Night\" },\n    1: { \"icon\": \"\\uE5A8\", \"text\": \"Sunny Day\" },\n\n    2: { \"icon\": \"\\uE590\", \"text\": \"Partly Cloudy (Night)\" },\n    3: { \"icon\": \"\\uE590\", \"text\": \"Partly Cloudy (Day)\" },\n\n    5: { \"icon\": \"\\uE591\", \"text\": \"Mist\" },\n    6: { \"icon\": \"\\uE591\", \"text\": \"Fog\" },\n    7: { \"icon\": \"\\uE590\", \"text\": \"Cloudy\" },\n    8: { \"icon\": \"\\uE590\", \"text\": \"Overcast\" },\n\n    9: { \"icon\": \"\\uE597\", \"text\": \"Light Rain Shower (Night)\" },\n    10: { \"icon\": \"\\uE597\", \"text\": \"Light Rain Shower (Day)\" },\n    11: { \"icon\": \"\\uE597\", \"text\": \"Drizzle\" },\n    12: { \"icon\": \"\\uE597\", \"text\": \"Light Rain\" },\n\n    13: { \"icon\": \"\\uE596\", \"text\": \"Heavy Rain Shower (Night)\" },\n    14: { \"icon\": \"\\uE596\", \"text\": \"Heavy Rain Shower (Day)\" },\n    15: { \"icon\": \"\\uE596\", \"text\": \"Heavy Rain\" },\n\n    16: { \"icon\": \"\\uE67F\", \"text\": \"Sleet Shower (Night)\" },\n    17: { \"icon\": \"\\uE67F\", \"text\": \"Sleet Shower (Day)\" },\n    18: { \"icon\": \"\\uE67F\", \"text\": \"Sleet\" },\n\n    19: { \"icon\": \"\\uE592\", \"text\": \"Hail Shower (Night)\" },\n    20: { \"icon\": \"\\uE592\", \"text\": \"Hail Shower (Day)\" },\n    21: { \"icon\": \"\\uE592\", \"text\": \"Hail\" },\n\n    22: { \"icon\": \"\\uE598\", \"text\": \"Light Snow Shower (Night)\" },\n    23: { \"icon\": \"\\uE598\", \"text\": \"Light Snow Shower (Day)\" },\n    24: { \"icon\": \"\\uE598\", \"text\": \"Light Snow\" },\n\n    25: { \"icon\": \"\\uE598\", \"text\": \"Heavy Snow Shower (Night)\" },\n    26: { \"icon\": \"\\uE598\", \"text\": \"Heavy Snow Shower (Day)\" },\n    27: { \"icon\": \"\\uE598\", \"text\": \"Heavy Snow\" },\n\n    28: { \"icon\": \"\\uE593\", \"text\": \"Thunder Shower (Night)\" },\n    29: { \"icon\": \"\\uE593\", \"text\": \"Thunder Shower (Day)\" },\n    30: { \"icon\": \"\\uE593\", \"text\": \"Thunder\" }\n})\n","finalize":"","libs":[],"x":790,"y":2200,"wires":[["86f80970b8ee2e35"]],"info":"0\tClear night\r\n1\tSunny day\r\n2\tPartly cloudy (night)\r\n3\tPartly cloudy (day)\r\n4\tNot used\r\n5\tMist\r\n6\tFog\r\n7\tCloudy\r\n8\tOvercast\r\n9\tLight rain shower (night)\r\n10\tLight rain shower (day)\r\n11\tDrizzle\r\n12\tLight rain\r\n13\tHeavy rain shower (night)\r\n14\tHeavy rain shower (day)\r\n15\tHeavy rain\r\n16\tSleet shower (night)\r\n17\tSleet shower (day)\r\n18\tSleet\r\n19\tHail shower (night)\r\n20\tHail shower (day)\r\n21\tHail\r\n22\tLight snow shower (night)\r\n23\tLight snow shower (day)\r\n24\tLight snow\r\n25\tHeavy snow shower (night)\r\n26\tHeavy snow shower (day)\r\n27\tHeavy snow\r\n28\tThunder shower (night)\r\n29\tThunder shower (day)\r\n30\tThunder"},{"id":"86f80970b8ee2e35","type":"function","z":"9fb2acebd1bf944c","name":"Organise \\n Chart Data","func":"/**\n * \n * { \n *   \"time\":\"2024-11-13T22:00Z\",\n *   \"screenTemperature\":11.41,\n *   \"maxScreenAirTemp\":12,\n *   \"minScreenAirTemp\":11.27,\n *   \"screenDewPointTemperature\":9.09,\n *   \"feelsLikeTemperature\":11.39,\n *   \"windSpeed10m\":0.34,\n *   \"windDirectionFrom10m\":332,\n *   \"windGustSpeed10m\":2.85,\n *   \"max10mWindGust\":4.41,\n *   \"visibility\":14251,\n *   \"screenRelativeHumidity\":86.36,\n *   \"mslp\":103540,\"uvIndex\":0,\n *   \"significantWeatherCode\":9,\n *   \"precipitationRate\":0.2,\n *   \"totalPrecipAmount\":0.09,\n *   \"totalSnowAmount\":0,\n *   \"probOfPrecipitation\":29,\n *   \"temperature\":11.41,\n *   \"humidity\":86.36,\n *   \"icon\":\"î–—\",\n *   \"description\":\"Light rain shower\",\n *   \"barometerChange\":\"rising\"\n * }\n * \n */\n\nconst forecastLocation = msg.payload.location.place\nconst runDate = (new Date(msg.payload.runDate)).toLocaleString('en-GB')\n\n// 'now' hour is start of current hour to ensure that the first data point in the chart is the CURRENT hour\nconst now = startOfHour().getTime()\n\nconst temperature = []\nconst precipitation = []\nconst windSpeed = []\nconst labels = []\nconst iconline = []                                                                         // Create line for icons to be above the temperature line\n\nconst iconLineLift = 4\n\nconst limit = 24\nlet itemCount = 0\nfor (const item of msg.payload.data) {\n    // Convert Met Office time to timeStamp. Note: Met Office time is UTC, automagically converted to BST or GMT\n    const itemTimestamp = (new Date(item.time)).getTime()\n\n    // only measurements in the future (and every hour for 24hrs)\n    if (itemTimestamp >= now && itemCount < limit) {\n        // Temperature\n        const currentTemperature = item.temperature\n        temperature.push(currentTemperature)\n\n        // Significant weather icon (Met Office icon number) and line detail\n        iconline.push( {line: fixedDecimals(currentTemperature + iconLineLift, 2),          // Raise icon a bit above temperature line\n                        iconNumber: item.icon,\n                        iconDescription: item.description})     \n        \n        // Rain / snow / sleet etc.\n        precipitation.push(item?.precipitation ?? 0)\n\n        // WindSpeed\n        windSpeed.push(item.windSpeed)\n        \n        // x Axis Labels. Local Hour\n        let timeString = ((new Date(itemTimestamp)).getHours()).toString().padStart(2, '0') + ':00'\n        labels.push(timeString)\n\n        itemCount++\n\n    }\n\n }\n\nmsg.payload = { \n                temperature,\n                precipitation,\n                windSpeed,\n                labels,\n                iconline,\n                forecastLocation,\n                runDate\n            }\n\nreturn msg\n\n\n    /********************************************************************\n    *\n    * Description       Set the given Date object to the current hour i.e hour, 0 minutes, 0 seconds, 0 microseconds\n    * \n    * @param    {Date}  [dirtyDate] - Date to find the start of hour of. Default: Date.now()\n    * \n    * @returns  {Date}              - A Date object with the time set to the current hour (0 minutes, 0 seconds, 0 microseconds)\n    * \n    */\n\n    function startOfHour(dirtyDate = Date.now()) {\n        const date = new Date(dirtyDate)\n        const hour = date.getHours()\n\n        date.setHours(hour, 0, 0, 0)\n\n        return date\n\n    } // End Function startOfHour()\n\n    /**\n    * Description   Ensure that there are only the number of required decimal points. Converts to a string of fixed decimal places then converts back to a number\n    * \n    * @param    {string | number}   originalNumber  - The item to check\n    * @param    {number}            decimalPlaces   - The number of decimal places required\n    * \n    * @return   {number}            - A number with the required number of decimal places, or no decimals if \n    *                                 returned number is an integer or only has 0 as the number after the decimal point\n    * \n    * @Note: 1. No checks of validity of passed parameters is made\n    *        2. This function just reduces the number of decimal places, it does NOT necessarily return that number of \n    *           decimal places. i.e. 21.0 returns as 21\n    *\n    * @Example let number = fixedDecimals(21.002, 1); => 21\n    *          let number = fixedDecimals(21.012, 2); => 21.01\n    */\n\n    function fixedDecimals(originalNumber, decimalPlaces) {\n        return parseFloat((originalNumber).toFixed(decimalPlaces));\n\n    } // End Function fixedDecimals()\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1070,"y":2200,"wires":[[]],"info":"/**\r\n * \r\n * { \r\n *   \"time\":\"2024-11-13T22:00Z\",\r\n *   \"screenTemperature\":11.41,\r\n *   \"maxScreenAirTemp\":12,\r\n *   \"minScreenAirTemp\":11.27,\r\n *   \"screenDewPointTemperature\":9.09,\r\n *   \"feelsLikeTemperature\":11.39,\r\n *   \"windSpeed10m\":0.34,\r\n *   \"windDirectionFrom10m\":332,\r\n *   \"windGustSpeed10m\":2.85,\r\n *   \"max10mWindGust\":4.41,\r\n *   \"visibility\":14251,\r\n *   \"screenRelativeHumidity\":86.36,\r\n *   \"mslp\":103540,\"uvIndex\":0,\r\n *   \"significantWeatherCode\":9,\r\n *   \"precipitationRate\":0.2,\r\n *   \"totalPrecipAmount\":0.09,\r\n *   \"totalSnowAmount\":0,\r\n *   \"probOfPrecipitation\":29,\r\n *   \"temperature\":11.41,\r\n *   \"humidity\":86.36,\r\n *   \"icon\":\"î–—\",\r\n *   \"description\":\"Light rain shower\",\r\n *   \"barometerChange\":\"rising\"\r\n * }\r\n * \r\n */\r\n\r\nconst forecastLocation = msg.payload.location.place\r\nconst runDate = (new Date(msg.payload.runDate)).toLocaleString('en-GB')\r\n\r\nconst days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']\r\nconst now = Date.now()\r\n\r\nconst temperature = []\r\nconst precipitation = []\r\nconst windSpeed = []\r\nconst labels = []\r\nconst icons = []\r\nconst iconline = []                                                                 // Create line for icons to be above the temperature line\r\n\r\nconst iconLineLift = 4\r\n\r\nlet lastDay = -1\r\nlet itemCount = 0\r\nlet limit = 24\r\nfor (const item of msg.payload.data) {\r\n    // Convert Met Office time to timeStamp. Note: Met Office time is UTC, automagically converted to BST or GMT\r\n    const itemTimestamp = (new Date(item.time)).getTime()\r\n\r\n    // only measurements in the future (and every other hour)\r\n    if (itemTimestamp >= now && itemCount < limit) {\r\n        // Temperature\r\n        const currentTemperature = item.temperature\r\n        temperature.push({x: itemTimestamp, y: currentTemperature})\r\n        \r\n        iconline.push({x: itemTimestamp, y: currentTemperature + iconLineLift})     // Raise icon a bit above temperature line\r\n        \r\n        // Rain / snow / sleet etc.\r\n        precipitation.push({x: itemTimestamp, y: item?.precipitation ?? 0})\r\n\r\n        // WindSpeed\r\n        windSpeed.push(item.windSpeed10m)\r\n        \r\n        // x Axis Labels. Local Hour\r\n        let timeString = ((new Date(itemTimestamp)).getHours()).toString().padStart(2, '0') + ':00'\r\n        labels.push(timeString)\r\n\r\n        // Significant weather icon (Met Office icon number)\r\n        icons.push(item.icon)\r\n\r\n        itemCount++\r\n\r\n    }\r\n\r\n }\r\n\r\nmsg.payload = { \r\n                temperature,\r\n                precipitation,\r\n                windSpeed,\r\n                labels,\r\n                icons,\r\n                iconline,\r\n                forecastLocation,\r\n                runDate\r\n            }\r\n\r\nreturn msg"}]

I have included below the CSS I use on the page for completeness (again, includes bits from posts by others)

	.height100 .v-card {
    	min-height: 100% !important;
	}

	.nrdb-ui-chart {
    	height: 288px !important;
	}

    .chart-title{
        text-align: center;
		font-size: 1.0em;

    }

    .centre-text {
        text-align: center;
        font-size: 0.8rem; 
    }

	.base-container {
    	width: 100%;
    	height: 100%;
    	justify-content: center;
    	align-items: center;
    	container: chat / size;     /* make this container available for container querys*/
    
	}

	.chart-container {
    	position: relative;
    	margin: auto;
    	height: 86cqb;              /* use container query units to give full height of the container (95% of container height) 
                                       to allow for title */
    	width: 100cqi;              /* use container query units to give full width of the container (100% of container height)*/
    	display: flex;
    	justify-content: center;
    	align-items: center;
	}
1 Like

Yes, this one works for me. I created a vue app to work from this template towards my own needs. Doing that in node-red is tedious since the smallest syntax error will just show an empty area. I haven´t figured out yet if and where the syntax check happens. Once the template works, i will just copy it back to node-red and hopefully it works :wink:

Thanks for the link, anyway!

I know this just creates more complication but if you right click on the blank chart and select 'Inspect (for Edge but probably similar for other browsers) the Console menu option will have a red cross. Select Console and it should give you a clue as to where the problem is