Thursday, 31 December 2015

Chart.js 2.0 in Ionic

There are lots JS data chart libraries... it's hard to choose one that's right for you. I started using chartjs because it's responsiveness, it has good support for users interactions and there is an angular directives that support it: angular-chart.js. Angulars directive support chart.js 1.0, after some attempts, I have had some issues:
  1. Time series aren't supported.
  2. It isn't simple to manage missing value.
Then I moved to chart.js 2.0, which was under development. Now, there is a beta version of the library.

So, as first step I have installed it with bower (at https://github.com/nnnick/Chart.js.git#v2.0-dev), and then I try to put it into a Ionic project.
I have put the chart inside a slider:

    <ion-nav-buttons side="left">
        <button class="button button-icon button-clear ion-navicon" menu-toggle="left">
        </button>
    </ion-nav-buttons>

    <ion-content>
        <ion-refresher on-refresh="doRefresh()" pulling-text="Pull to refresh...">
        </ion-refresher>

        <ion-slide-box animation="slide-left-right-ios7" show-pager="true">
            <ion-slide>
                <div class="list card">
    <div class="item">
      First series
                  </div>
    <div class="item item-body">
      <canvas class="chart" height="300" id="firstPlot"></canvas>
    </div>
       </div>
   </ion-slide>
        <ion-slide>
   <div class="list card">
     <div class="item">
  Second
            </div>
     <div class="item item-body">
       <canvas class="chart" height="300" id="secondPlot"></canvas>
            </div>
 </div>
      </ion-slide>
   </ion-slide-box>
  </ion-content>
 </ion-view>
And the controller code:
     
angular.module('myModule', [])controller('chartCtrl', function ($scope, $ionicSlideBoxDelegate,
 $stateParams, $sce , getMyDataServices) {
    Chart.defaults.global.pointHitDetectionRadius = 1;
    Chart.defaults.global.datasetFill = false;
    /*dataToPlot contains 2 series chart1 (which is an array of dimension 3xn => [[],[],[]])
    / and chart2 which is an array 1xn
    / dataToPlot.data contains the labels for x axis.
    */
    var dataToPlot=getMyDataServices.getDataToPlot();
    var chart1=null;
    var chart2=null;
    //if I want to plot an interval.
    var l = dataToPlot.data.length - 1;
    var start = 0;
    //if I want to formatting the data
    var labels = dataToPlot.data.map(function (d) {
                return d;
            });
    chart1 = createPlot(chart1, {series: [dataToPlot.chart1], serieLabel: ["Plot1 "],
                                labels: labels, 
                                colors:['rgb(0, 0,255)','rgb(0, 0, 0)', 'rgb(255, 0, 0)']},
                                start, end, "#plot1a", "[-]");
    chart2 = createPlot(chart2, {series: [dataToPlot.chart2], serieLabel: ["Plot2 "],
                        labels: labels, colors: ['rgb(0, 0, 255)']},
                         start, end, "#plot2", "[-]");

    //update
    $scope.$broadcast('scroll.refreshComplete');
    $ionicSlideBoxDelegate.update();
    $scope.$broadcast('scroll.refreshComplete');

    $scope.doRefresh = function () {
        getData();
        $ionicSlideBoxDelegate.update();
    };
});


var opt = {
    tooltips: {
        mode: 'label'
    },
    hover: {
        mode: 'label'
    },
    scales: {
        xAxes: [{
                display: true,
                scaleLabel: {
                    show: true
                }
            }],
        yAxes: [{
                display: true,
                scaleLabel: {
                    show: true,
                    labelString: "void"
                }
            }]
    }, elements: {
        line: {
            borderCapStyle: 'round',
            borderWidth: 1.0,
            tension: 0.1
        },
        point: {
            backgroundColor: Chart.defaults.global.defaultColor,
            borderWidth: 1,
            borderColor: 'rgb(0,0,0)',
            hitRadius: 10,
            hoverRadius: 5,
            hoverBorderWidth: 1,
            radius: 2
        }
    }
};



var createPlot = function (plot, dataToPlot, start, end, id, scaleLabel) {
    opt.scales.yAxes[0].scaleLabel.labelString = scaleLabel;
    var dataset = [];
    if (!!dataToPlot.series) {
        for (var i = 0; i < dataToPlot.series.length; i++) {
            if (!!dataToPlot.series[i]) {
                dataset.push({
                    label: dataToPlot.serieLabel[i],
                    data: dataToPlot.series[i].slice(start, end).map(function (x) {
                         //parse the value to int, only for me                   
                          return parseInt(x, 10);
                    }),
                    fill: false,
                    borderColor: dataToPlot.colors[i]
                });

            }
        }
        var config = {
            type: 'line',
            data: {
                labels: dataToPlot.labels.slice(start, l),
                datasets: dataset
            },
            options: opt
        };
        if (plot !== null) {
            plot.destroy();
        }
        var ctx = angular.element(document.querySelector(id));
        plot = new Chart(ctx, config);

        return plot;
    }
};



No comments:

Post a Comment