How to pass dynamic/static data for Chart JS <canvas> in Meteor

For example we have static implementation of chart js with data that we can’t update

JS

import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import Chart from 'chart.js';
import './barChart.html'

let barChartData = {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: 'My First dataset',
        data: [11, 22, 33, 44, 55, 66],
        backgroundColor: [
            'rgba(255, 99, 132, 0.2)',
            'rgba(54, 162, 235, 0.2)',
            'rgba(255, 206, 86, 0.2)',
            'rgba(75, 192, 192, 0.2)',
            'rgba(153, 102, 255, 0.2)',
            'rgba(255, 159, 64, 0.2)'
        ],
        borderColor: [
            'rgba(255,99,132,1)',
            'rgba(54, 162, 235, 1)',
            'rgba(255, 206, 86, 1)',
            'rgba(75, 192, 192, 1)',
            'rgba(153, 102, 255, 1)',
            'rgba(255, 159, 64, 1)'
        ],
        borderWidth: 1
    }]
}

let barChartOptions = {
    scales: {
        yAxes: [{
            ticks: {
                beginAtZero:true
            }
        }]
    }
}

Template.barChart.helpers(barChartData);
Template.barChart.helpers(barChartOptions);

Template.barChart.onRendered(function () {
      console.log("barChart is rendered")
      let ctx = $("#barChart");
      let myBarChart = new Chart(ctx, {
        type   : 'bar',
        data   : barChartData,
        options: barChartOptions
      });

});

Example HTML

{{> barChart}}  

<template name='barChart'>
   <canvas id="barChart" width="400" height="200"></canvas>
</template>

How to pass data/options to Chart JS from (local collection or server collection or some query), using Template helpers for updating chart in live? or for testing update that data from console

The simplest solution is to ensure that the chart can be redrawn reactively:

Template.barChart.onRendered(function () {
  console.log("barChart is rendered")
  let ctx = $("#barChart");
  this.autorun(() => {
    let myBarChart = new Chart(ctx, {
      type   : 'bar',
      data   : barChartData,
      options: barChartOptions
    });
  });
});

And then make barChartData reactive - so that could be as a ReactiveVar or a Collection.find().fetch() for example.

1 Like

Rob, thank you a lot!

1 Like

Hi Rob,

Do you have an example of using Collection.find().fetch() ? Would that be inside the autorun or before?

I’m having trouble with creating a reactive chart while trying to sort and limit the data on the collection. It seems as if the chart is cycling through all of the data before reaching the end / most recent data, which is all I want to show.

Here’s my current code:

Template.chart.onRendered(function() {

    var controller = Iron.controller();

    var params = controller.getParams();
 
    var sensor = params.sensorId;
    var device = params.deviceId;

    // Makes sure that this reruns every time collection is updated
    this.autorun(() => {

        // Get the context of the canvas element we want to select
        var ctx  = document.getElementById("myChart").getContext("2d");

        var sensorTimeString = 'data.' + sensor + '.ts';
        var sensorValueString = 'data.' + sensor + '.value';
        
        var query = {};
        query.deviceId = device;
        query[sensorTimeString] = {$exists: true};

        var options = {};
        var sortDirection = {};
        sortDirection[sensorTimeString] = -1;
        options.sort = sortDirection;
        options.limit = 15;

        var dataFetch = IotHubEvents.find(query,options).fetch();
        var dataPoints = [];
        var labels = [];

        dataFetch.forEach(function(e) {
                dataPoints.push(e["data"][sensor]["value"]);
                labels.push((new Date(e["data"][sensor]["ts"])).toLocaleTimeString()); 
            });

        // Set the options
        var options = {

            ///Boolean - Whether grid lines are shown across the chart
            scaleShowGridLines: true,

            //String - Colour of the grid lines
            scaleGridLineColor: "rgba(0,0,0,.05)",

            //Number - Width of the grid lines
            scaleGridLineWidth: 1,

            //Boolean - Whether to show horizontal lines (except X axis)
            scaleShowHorizontalLines: true,

            //Boolean - Whether to show vertical lines (except Y axis)
            scaleShowVerticalLines: true,

            //Boolean - Whether the line is curved between points
            bezierCurve: true,

            //Number - Tension of the bezier curve between points
            bezierCurveTension: 0.4,

            //Boolean - Whether to show a dot for each point
            pointDot: true,

            //Number - Radius of each point dot in pixels
            pointDotRadius: 4,

            //Number - Pixel width of point dot stroke
            pointDotStrokeWidth: 1,

            //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
            pointHitDetectionRadius: 20,

            //Boolean - Whether to show a stroke for datasets
            datasetStroke: true,

            //Number - Pixel width of dataset stroke
            datasetStrokeWidth: 2,

            //Boolean - Whether to fill the dataset with a colour
            datasetFill: true,

            //String - A legend template
            legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"

        };

        // Set the data
        var data = {
            labels: labels.reverse(),
            datasets: [{
                label: "ADC Telemetry",
                fillColor: "rgba(220,220,220,0.2)",
                strokeColor: "rgba(220,220,220,1)",
                pointColor: "rgba(220,220,220,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: dataPoints.reverse()
            }]
        };

        // draw the charts
        var myLineChart = new Chart(ctx, {
            type: 'line',
            data: data,
            options: options
        });
    });
});