Dashboard 2.0 ui-Template

Good Day, i need some help please new to node-red, i have managed to bring in google charts in Dashboard 2.0 using a ui-template node. With in the code i would like to inject my values. But i have been unable to find a way to pull variables from the msg.payload i send to the ui-template.


<head>
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  <script type="text/javascript">
    google.charts.load('current', {'packages':['corechart', 'bar']});
      google.charts.setOnLoadCallback(drawStuff);

        function drawStuff() {

        //var button = document.getElementById('change-chart');
        var chartDiv = document.getElementById('chart_div');

       *Would like to inject my values*
        var data = google.visualization.arrayToDataTable([
          ['Galaxy', 'Distance', 'Brightness'],
          ['Canis Major Dwarf', 8000, 23.3],
          ['Sagittarius Dwarf', 24000, 4.5],
          ['Ursa Major II Dwarf', 30000, 14.3],
          ['Lg. Magellanic Cloud', 50000, 0.9],
          ['Bootes I', 60000, 13.1]
        ]);

        var materialOptions = {
          width: 900,
          chart: {
            title: 'temp', *Would like to inject my values*
            subtitle: 'distance on the left, brightness on the right'
          },
          series: {
            0: { axis: 'distance' }, // Bind series 0 to an axis named 'distance'.*Would like to inject my values*
            1: { axis: 'brightness' } // Bind series 1 to an axis named 'brightness'.*Would like to inject my values*
          },
          axes: {
            y: {
              distance: {label: 'parsecs'}, // Left y-axis.*Would like to inject my values*
              brightness: {side: 'right', label: 'apparent magnitude'} // Right y-axis.*Would like to inject my values*
            }
          }
        };

          function drawMaterialChart() {
          var materialChart = new google.charts.Bar(chartDiv);
          materialChart.draw(data, google.charts.Bar.convertOptions(materialOptions));
          button.innerText = 'Change to Classic';
          button.onclick = drawClassicChart;
          }
          
          function drawClassicChart() {
          var classicChart = new google.visualization.ColumnChart(chartDiv);
          classicChart.draw(data, classicOptions);
          button.innerText = 'Change to Material';
          button.onclick = drawMaterialChart;
          }
          
          drawMaterialChart();
          };
  </script>
</head>

<body>
  
  <br><br>
  <div id="chart_div" style="width: 800px; height: 500px;"></div>

</body>type or paste code here

Any point in the right direction would be appreciated.

A post was split to a new topic: How to do two way binding

Moved unrelated question to own topic

So this isn't a full solution, but does show how you can transfer some of the behaviour you have into a Vue Component with ui-template such that you can get easy access to the msg.payload value:

<template>
    <div ref="g-chart"></div>
</template>

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

<script>
    export default {
    mounted () {
        // code runs here when the component is first loaded
        let interval = setInterval(() => {
          if (window.google) {
            // call a draw function to utilise the Google Charts library
            draw();
            // Google Charts has loaded now, so we can use it
            clearInterval(interval);
          }
        }, 100);
    },
    watch: {
      value: {
        // watch the "value" of the template node,
        // which under the covers in ui-template is msg.payload
        handler: function (payload) {
          // update your chart with some data
          var data = window.google.visualization.arrayToDataTable(payload);
          // ... do something with data
          // e.g. this.draw()
        },
        deep: true
      }
    },
    methods: {
      draw: function () {
        // ensure we have persistent access to the vue object,
        // even inside our own function () { ... } definitions where this. is re-assigned
        const vue = this
        // easier reference to window.google object
        const google = window.google

        // ... draw the chart and use vue.value which will be the latest received msg.payload
      }
    }
  }
</script>

I've not transferred everything over, but have tried to at least offer the scaffolding. I had issues whereby window.google.visualization is coming back undefined, but that'll be a Google Charts problem rather than something I can help with.

1 Like

Good morning that you so the assist i will give if a go.

Good Day, joepavitt

Sorry to bother you again with this, but i have been unable to get this code to work. I have been through 20+ iteration, but just end up with errors. My understanding of the coding is very bad.

<template>
    <div id="chart_div" style="width: 100%; height: 300px;"></div>
</template>

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

<script>
    export default {
      data: {
        value: 0, // Initial value
        chartData: [['Category', 'Value'], ['Initial', 0]] // Initial chart data
      },
      mounted : function() {
        // Load Google Charts library
        google.charts.load('current', {'packages':['corechart']});
        // Set a callback function to draw the chart when the library is loaded
      google.charts.setOnLoadCallback(this.drawChart);
    },
    watch: {
      value: function(newValue) {
    // Update chart data when value changes
      this.chartData[1][1] = newValue;
    // Redraw the chart
      this.drawChart();
    }
    },
    methods: {
        // Method to draw or redraw the chart
        drawChart: function() {
        var data = google.visualization.arrayToDataTable(this.chartData);
        var options = {
        title: 'My Chart',
        width: '100%',
        height: 300
     };
      var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
      chart.draw(data, options);
     }
    }
}
</script>

Any more pointers will be appreciated.

I know this does not help you right now but I'm bringing this up because what your trying to do, I do, all the time in the original dashboard.
https://gist.github.com/TotallyInformation/2f1aaf0635f9bf23207152682323240a#bonus-pass-html-dynamically-to-the-dashboard-ui

I create a msg.payload contatining what I want the template to be.

1 Like

Hi thanks i will check it out at the moment anything will be helpful.

Can that really be me writing? About Dashboard and not UIBUILDER?! :slight_smile:

2 Likes

Hey @jwj001 not going to get a chance to dive into this heavily today, but a quick pointer is the content of your mounted:

// Load Google Charts library
google.charts.load('current', {'packages':['corechart']});
// Set a callback function to draw the chart when the library is loaded
google.charts.setOnLoadCallback(this.drawChart);

The google script would likely not have loaded at this point, as mounted runs as soon as the page loads, not necessarily, once your <script /> tag has fully loaded the Google Charts library.

Instead, you'll want to make the most of the interval I provided above, which checks when when the google charts library has loaded. Reasoning for this piece of code is justified in the docs here

Hi joepavitt..

Thanks for the assist i managed to get it going...

<template>
  <div>
    <div id="columnchart_material" style="width: 1200px; height: 600px;"></div>
  </div>
</template>

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

<script>
  export default {
  mounted () {
    // Load Google Charts library
    google.charts.load('current', {'packages':['bar']});
    // Set a callback function to draw the chart when the library is loaded
    google.charts.setOnLoadCallback(this.drawChart);
  },
  watch: {
    value: {
      // Watch the "value" of the template node,
      // which under the covers in ui-template is msg.payload
      handler: function (payload) {
        // Update your chart with the new data
        this.updateChart(payload);
      },
      deep: true
    }
  },
  methods: {
    drawChart: function () {
      // Default data for the chart
      var data = google.visualization.arrayToDataTable([
        ['Year', 'Sales', 'Expenses', 'Profit'],
        ['2014', 1000, 400, 200],
        ['2015', 1170, 460, 250],
        ['2016', 660, 1120, 300],
        ['2017', 1030, 540, 350]
      ]);

      var options = {
        chart: {
          title: 'Company Performance JK 2024',
          subtitle: 'Sales, Expenses, and Profit: 2014-2017',
        }
      };

      // Draw the chart
      var chart = new google.charts.Bar(document.getElementById('columnchart_material'));
      chart.draw(data, google.charts.Bar.convertOptions(options));
    },
    updateChart: function (payload) {
      // Update the chart with new data
      var data = google.visualization.arrayToDataTable(payload);
      // Redraw the chart with updated data
      var chart = new google.charts.Bar(document.getElementById('columnchart_material'));
      chart.draw(data);
    }
  }
}
</script>

Thanks for the pointers