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


#1

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


#2

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.


#3

Rob, thank you a lot!


#4

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
        });
    });
});