Modular charts in Ionic?

Hi there, I’m dealing with a simple issue, i’m in the hunt for a good chart library, a modular library that i can import just what i need, the reason to the need of modularity is that in a mobile app modularity is key to keeping the app size low, i have tried d3 but it’s very complex, going for charts.js can’t do as there’s some errors to sort through, ng2-charts is based on charts.js so some issues as well, highcharts is big and is non-free for comercial purposes, at least 3 times the size of d3, and there’s just primeng which is modular but uses System.js so i can’t use it in webpack (what a shame), any recomendation? i only need a bar chart and a dougnut chart.

So there’s a few things you can do here

D3 - Have you looked at C3? Looks like a much more saner approach to using D3

charts.js/ng2-charts - Curious to what errors you were facing?

primeng - So just because a particular package uses system.js in their docs, doesn’t mean you are tied to that. With ionic’s build system, you can still npm install that package, and webpack will load it for you.

1 Like

@mhartington Thanks for fast answer:

  1. I’ll look right now at C3.
  2. ng2-charts forgot the error, testing again but the starter doesn’t transpile, have the starters already changed to browserify?
  3. That’s what i haven’t been able to do, i did install it, try to load it, but when used it then it broke saying System is not defined or something like that.

Ahh I see, looking into their code, yeah looks like primeng is not setup for common.js/es6 modules.

The starters have not been moved over to browserify yet, they’re still on webpack.
If you could post the error, I’d be curious to see what it is and if we can fix it. I don’t suspect it to be anything crazy.

@mhartington C3 seems very good, but how would i load it with webpack in that specific page? it’s not made by modules right? is importing in index.html the sources of both D3 and C3 the only option? my users doesn’t use the charts all the time, it’s more like a nice side feature that should be there but isn’t used often, loading it always just doesn’t seem right.

@mhartington Oops, forget about that error, just updated the ionic-cli and started a new project and it works again, as for the ng2-charts error i get it’s about not finding Charts object:

EXCEPTION: ReferenceError: Chart is not defined in [barChartOptions in GettingStartedPage@22:11]

I think it has to do with i not including the file of charts and jus calling the charts directives from the ES6 file:

<script src="node_modules/chart.js/Chart.min.js"></script> // I'm not calling this in my index.html
import {CHART_DIRECTIVES} from 'ng2-charts/ng2-charts'; // This is the one i use and expect to load in the page

How would i call the Chart.min.js from the page, like this?:

import {Charts} from 'ng2-charts/components/charts/charts.ts';

@mhartington C3 looks a lot sane that D3, but as it has D3 as dependency i suspect it will bump a bit the app size, i’m looking forward to fix the ng2-charts one and use that one, i’ll leave C3 as last resort.

I have a working example of NG2-Charts (Charts.JS) + Ionic 2 here

I don’t get it, if you have the charts.ts file in same folder why bother installing ng2-charts with npm?
Also does it work? mine don’t even if i import the CHART_DIRECTIVES from the right module, it keeps saying to me that Chart is not defined.

Update1: Oh i see you’re importing within index.html the <script src="Chart.min.js"></script> and i lack that part in mine, is there a way to do it with the bundle process of webpack? or with an import in the same page?.

So in this case, I think there’s some confusion about the modular aspect of things. So when you have your chart library, it still will include all the unused code. There is not dead-code elimination yet, so even if you only import bar charts, you’ll still get the code for all the other kind of charts, At the moment. So at this point in time, you can pick which ever chart lib works.

I’m working on a chartjs example thats a bit more stream-lined.

Oh I have charts.ts in the same folder because back when I created this test app there was a bug with ng2-charts… See my PR here: https://github.com/valor-software/ng2-charts/pull/38
NG2-Charts didn’t work with Ionic without that PR ( + some CSS )

to merge Chart.min.js just add the file in the entry array in webpack.config.js

I look forward to checkout your example.

So i need to install both ng2-charts and charts.js? if so shouldn’t they put it as a peer dependency or something?

In the demo example they are importing it. It’s also the 3rd step to install ng2-charts.

https://github.com/valor-software/ng2-charts/blob/master/demo/index.html#L36

As I understand ng2-charts is just an interface/declaration for the charts.js functions. Makes it easier to call those functions directly from your Angular 2 application if you are writing it in TypeScript.

Done what you said but it still shows the error.

Getting this error in your .ts file is fine … Since Chart is defined in Chart.min.js

In my example I didn’t have to use Chart anyways in my typescript file … https://github.com/ihadeed/charttest/blob/master/app/pages/page1/page1.ts

Not sure why are you referring to Chart?

I used the barChart example of the ng2-charts site, i also don’t understand where in the world that `Chart variable is being called:

// webpack.config.js
module.exports = {
  entry: [
    path.normalize('es6-shim/es6-shim.min'),
    'reflect-metadata',
    path.normalize('zone.js/dist/zone-microtask'),
    'chart.js/chart.min',
    path.resolve('app/app')
  ], // From here default ionic project
<!-- app/pages/getting-sterted/getting-started.html -->
<ion-navbar *navbar>
  <button menuToggle>
    <ion-icon name="menu"></ion-icon>
  </button>
  <ion-title>Getting Started</ion-title>
</ion-navbar>
<ion-content padding class="getting-started">

  <h3>Getting Started</h3>
  <p>
     Get it started!
  </p>
  <p>
    <button primary menuToggle>Toggle Menu</button>
  </p>

  <base-chart class="chart"
           [data]="barChartData"
           [labels]="barChartLabels"
           [options]="barChartOptions"
           [series]="barChartSeries"
           [legend]="barChartLegend"
           [series]="barChartSeries"
           [chartType]="barChartType"
           (chartHover)="chartHovered($event)"
           (chartClick)="chartClicked($event)"></base-chart>
</ion-content>
// app/pages/getting-sterted/getting-started.ts
import {Page} from 'ionic-angular';
import {CHART_DIRECTIVES} from 'ng2-charts/ng2-charts';

@Page({
  templateUrl: 'build/pages/getting-started/getting-started.html',
  directives: [CHART_DIRECTIVES]
})
export class GettingStartedPage {
  constructor() {
  }

  private barChartOptions = {
    scaleShowVerticalLines: false,
    responsive: true,
    multiTooltipTemplate: '<%if (datasetLabel){%><%=datasetLabel %>: <%}%><%= value %>'
  };
  private barChartLabels = ['2006', '2007', '2008', '2009', '2010', '2011', '2012'];
  private barChartSeries = ['Series A', 'Series B'];
  public barChartType = 'Bar';
  private barChartLegend: boolean = true;

  private barChartData = [
    [65, 59, 80, 81, 56, 55, 40],
    [28, 48, 40, 19, 86, 27, 90]
  ];

  // events
  chartClicked(e: any) {
    console.log(e);
  }
  chartHovered(e: any) {
    console.log(e);
  }
}

Just an example, seems ngCharts is a bit early to use.
Put together a simple example of using c3.js instead.
Was a much easier process and felt like a natural fit for ionic’s build process.

Key things I want to point out.

C3 has it’s own styles, and scss files, so they’re easy to include in ionic’s build process.

You also need to make sure that you wait until the view has been fully initiated.

1 Like

Yep, the ngAfterViewInit() was expected, D3 forced me to do the same, thanks @mhartington.

Btw i have been trying to make the numeric pipe work in IOS and as my research goes IOS doesn’t support the internationalisation api, so i’ve been told i have to use an intl polyfill, how should i go about adding that one to the build process with webpack since it only should be included in devices that doesn’t support the intl api?

When using a library that does support ES6 modules and is build with modules in mind, i tough that if you just imported 1 module of a library webpack would just transpile the imported part and the dependencies of it, is the issue here that these libraries aren’t made with modules in mind?