Olly John
Olly John

Reputation: 384

Dynamically set chart type with Angular Chart?

I'm currently working on a data driven app with the Ionic Framework and AngularChart, and I'm reaching the stage now where the UI is mostly designed and now I need to start thinking about how I can display the data for the users to see. Obviously, I've decided to use AngularChart as I have a bit of experience working with Chart.js and Angular so it makes sense really!

I've defined a couple of static charts in a sandbox environment with no issues but ideally I'd be setting the class of the canvas to define the chart type according to a value from a JSON array that I pull the rest of the data from (see below)

The aforementioned JSON array is the below:

[
    {
        "name": "Fitness",
        "chart_type": "chart chart-line"
    },
    {
        "name": "Performance",
        "chart_type": "chart chart-line"
    },
    {
        "name": "Weightlifting",
        "chart_type": "chart chart-line"
    },
    {
        "name": "Anthropometrics",
        "chart_type": "chart chart-line"
    },
    {
        "name": "Sport specific test",
        "chart_type": "chart chart-line"
    },
    {
        "name": "Sport lab test",
        "chart_type": "chart chart-line"
    } 
]

One of these array elements is selected from a menu and stored in $scope.metric in the controller, where it is accessible for the next screen (code below) so the data can be displayed in the right chart format. Obviously they're all the same at the moment but when I get further into the project they will be different, so I want to try and do it dynamically.

The code the the view which should show the chart is the below:

<ion-view>
  <div class="bar bar-header bar-stable">
    <button class="button button-stable button-outline" ng-click="go('home')">
      <i class="icon ion-ios-home"></i>
    </button>
    <h1 class="title">{{ metric.name }}</h1>
    <button class="button button-stable button-outline" ng-click="logOut()">
      Log out
    </button>
  </div>
  <ion-content>
    <h2>{{ metric.name }} scores</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
      dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      <br/>
      <br/>
    </p>
    <canvas id="line" class="{{metric.chart_type}}" chart-data="data" chart-labels="labels" chart-series="series" chart-options="options" chart-dataset-override="datasetOverride" chart-click="onClick"></canvas>
  </ion-content>
</ion-view>

I know that the metric object is being stored correctly as the {{metric.name}} parts are displaying the correct thing and if I inspect element on the canvas where the chart should be rendered, I can see that the class is correct as well, yet the chart doesn't render, as per the below screenshot.

The rendered canvas (or lack thereof) and computed class

I'm not really sure where I'm going wrong with this so any helpwould be greatly appreciated.

EDIT - Added relevant controller

angular.module('app')
  .controller('metric_ctrl', function($scope, $state, user_svc, metric_svc, $ionicHistory) {

    $scope.metricOptions = [{
      "name": "Fitness",
      "chart_type": "chart chart-line"
    }, {
      "name": "Performance",
      "chart_type": "chart chart-line"
    }, {
      "name": "Weightlifting",
      "chart_type": "chart chart-line"
    }, {
      "name": "Anthropometrics",
      "chart_type": "chart chart-line"
    }, {
      "name": "Sport specific test",
      "chart_type": "chart chart-line"
    }, {
      "name": "Sport lab test",
      "chart_type": "chart chart-line"
    }];
    $scope.scores = metric_svc.getScores();
    $scope.metric = metric_svc.getMetric();

    // console.log($scope.metric.chart_type);


    $scope.labels = ['T1', 'T2', 'T3', 'T4'];
    $scope.series = ["Weight (Kg)", "BMI (%)"];
    $scope.data = [
      [64, 67, 70, 73],
      [17.3, 18.4, 19.2, 20.1]
    ];
    $scope.options = {
      scales: {
        yAxes: [{
          id: 'y-axis-1',
          type: 'linear',
          display: true,
          position: 'left',
          scaleLabel: {
            display: true,
            labelString: "Weight (Kg)"
          }
        }, {
          id: 'y-axis-2',
          type: 'linear',
          display: true,
          position: 'right',
          scaleLabel: {
            display: true,
            labelString: "BMI (%)"
          }
        }]
      }
    };
    $scope.datasetOverride = [{
      yAxisID: 'y-axis-1'
    }, {
      yAxisID: 'y-axis-2'
    }];


    $scope.logOut = function() {
      $scope.user = {};
      user_svc.setUser($scope.user);
      $state.go('login');
    };

    $scope.setMetric = function(metric) {
      // console.log('Setting metric to ' + metric);
      $scope.metric = metric;
      metric_svc.setMetric(metric);
      $state.go('metrics_value')
    }

    $scope.getScores = function() {
      $scope.scores = metric_svc.getScores();
      // console.log($scope.scores);
    }

  })

Upvotes: 0

Views: 2299

Answers (1)

Olly John
Olly John

Reputation: 384

So after a great deal of frustration trying to figure out why the scoped variable wasn't mutating the DOM how I'd wanted, I returned to the AngularChartJS documentation and found really rather a simple solution.

If you set the class of the canvas to chart chart-base, it's possible to set the chart type by simply providing the canvas with a chart-type attribute and setting it to whatever the scoped variable is called. In my case, this was the markup I ended up with to reach the outcome that I needed where, of course, chart_type is the variable held in the controller.

<canvas class="chart chart-base" chart-type="chart_type" chart-data="data" chart-labels="labels" chart-series="series" chart-options="options" chart-dataset-override="datasetOverride" chart-click="onClick"></canvas>

Upvotes: 2

Related Questions