Angularweb design

Charts with Angular: ngx-charts (Formerly: ng2d3)

Originally, I wanted to write an article about ng2d3. That’s a fine library bringing the power of D3.js charts to the Angular2 world without the price. D3 requires you to adopt a special programming style. You have to learn and use a new programming paradigm, the data-driven programming style. ng2d3 doesn’t require such a thing. You just pass it the data, and it’ll draw the diagram for you.

The only problem with ng2d3 is that it doesn’t exist anymore. More precisely, when I started writing, the team published a new major version (including a couple of breaking changes) and changed the name of the project. Now it’s called ngx-charts. In the view of the new semantic versioning strategy of Angular, the name makes a lot of sense. Calling a framework “ng2-something” won’t work when Angular4 will have been published, skipping Angular3 altogether.

The new name makes even more sense in that it focuses on charts, not on a particular framework to generate charts. D3.js may be the basis of ngx-charts, but it’s both famous and dreaded for its particular approach to drawing charts. I’ve already mentioned the data-driven approach. Plus, using D3.js amounts to care about every aspect of your chart. If you need such a simple thing as an x-axis, you have to write several lines of code for it. That’s not the declarative approach most people prefer.

By the way, I should mention that learning D3 is worth the trouble. Once you’ve understood how D3.js works, you can generate awesome animated and interactive graphics.

What makes ngx-charts different from using D3 directly

Nonetheless, the nice thing about ngx-charts is that it allows you do draw charts in a more traditional way. You pass your chart data to the library, and that’s all you have to do. ngx-charts adds all the small details, including legends, tool-tips, call-backs for user interaction and even some animations.

What makes ngx-charts different from other Angular chart libraries

Before finding ngx-charts, I’ve also tested a couple of other chart libraries. They aren’t bad, but in my eyes, ngx-chart has an edge with respect to features and flexibility. For instance, the one feature we needed isn’t supported by any library I’ve tested: line charts which aren’t smooth but stepped. My business use case required this kind of charts, but even such a popular library as Valor Software’s ng2-chart insists on drawing smooth lines. ngx-charts gives you both options (and quite a few more).

Architecture of ngx-charts

Many chart libraries draw their charts in a canvas or in an SVG image that’s not linked to the life cycle events of Angular. As a consequence, many of these static images aren’t redrawn when the window size is changed. ngx-charts adds an interesting twist: it uses D3.js to do the math but leaves the actual drawing to Angular. This way, you’ve got the best of both worlds.

As it turns out, that sound’s more difficult than it is. The idea is simply to define the SVG elements as components. For instance, a radically simplified bar chart looks like so:

@Component({
  selector: 'g[ngx-charts-series-horizontal]',
  template: `
    <svg:path 
      *ngFor="let bar of bars"
      [attr.d]="path(bar.x, bar.y, bar.width, bar.height)" />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: [ ... ],
})
export class SeriesHorizontal implements OnChanges {
   path(x, y, width, height: number): String {
     return `M ${x} ${y} h ${width} v ${height}`;
   }
}

You’ll recognize the familiar building blocks of Angular. The SVG magic is generated as ordinary HTML code in the template. In this case, it’s an SVG path that’s repeated for every bar in the data set. The coordinates of the path are calculated in a function of the component. Usually, the gory details of the path definition are usually left to D3.js. But that’s a small price to pay for a decent integration with Angular.

Walkthrough

I had some difficulties starting with ngx-charts because the examples provided by the project don’t exactly match the project structure of the Angular CLI. To help you to get started, I’ve provided a minimal example at my GitHub repository. At the time of writing, there’s only one simple example (the line chart), and a complex example showing how to use the charts in a real-world application. Over time, I’ll add more examples if time allows. Just in case you’re confused by the weird class names: the complex example shows the fuel consumption of my last two cars, and I’ve derived the simple example from it.

I gather you’ve already got node.js, npm, and the latest Angular CLI installed. I also omit the steps that are well documented, pointing out only the project setup because that’s what proved to be difficult. To create the project, type this command on the command line:

ng new my-charts
cd my-charts

Next, you need to add ngx-charts and D3.js to your project:

ng g component consumption-component
npm install @swimlane/ngx-charts --save
npm install d3 --save
npm install @types/d3 --save-dev

At this point, the examples provided by the ngx-charts team seem to be a bit odd. They’re using a D3.d.ts file hidden (or exposed, depending on your point of view) in the node-modules folder of the ngx-charts project. I didn’t feel comfortable to use such a local resource, so I decided to use one of the official type definitions of D3. However, there’s no typings definition, so I had to use a @types definition. That, in turn, defines a couple of variables slightly differently. So you can’t simply copy the examples from the Plunker examples embedded in the documentation. Instead, you have to modify some of them. Cutting a long story short: probably you’re better off using the internal D3.d.ts of ngx-charts, which results in imports statements like

import d3 from '@swimlane/ngx-charts/release/d3';

Be that as it may, you also need to include a CSS file. The easiest way to do this is to add it to the angular-cli.json like so:

...
"styles": [
   "styles.css",
   "../node_modules/@swimlane/ngx-charts/release/ngx-charts.css"
],
...

The rest is more-or-less plain vanilla. You add the NgxChartsModule to your @NgModule:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    NgxChartsModule
  ],
  exports: [],
  bootstrap: [AppComponent]
 })
export class AppModule {
}

Basically, that’s all you need to know to use the examples of the ngx-charts documentation. I could list the HTML file and the Typescript file of the component, but they don’t add much information. Better import my demo project from GitHub into your IDE and start modifying it yourself.

Wrapping it up

If you just want to create a beautiful chart quickly without having to learn a lot of things first, I (currently) recommend ngx-charts. It integrates nicely with both Angular and D3.js, it’s pretty popular and the resulting charts look great. It’s a nice compromise between ease-of-use and a rich feature set.


Dig deeper

ngx-charts project page on GitHub
ngx-charts live demo
ngx-charts documentation

13 thoughts on “Charts with Angular: ngx-charts (Formerly: ng2d3)

  1. Dear Stephan, this is a great article, but I am having issue to display chart data in case of it is an Observable, so the async pipe is needed like this below:

    [results]="single | async"
    

    Did you manage to run with this observable approach?

    for example the ‘simple’ data should be this:

    getSingle = () =&gt; Observable.of([
        {
          'id': 1,
          'name': 'Germany',
          'value': 8940000
        },
        {
          'id': 2,
          'name': 'USA',
          'value': 5000000
        },
        {
          'id': 3,
          'name': 'France',
          'value': 7200000
        }
      ]).delay(2000);
    

    Thanks for your feedback, Attila

    1. I don’t see any reason why async shouldn’t work. But I have to admit I avoided it, as you can see in my demo repository at GitHub. These are the key lines of the program:

      public leon: ConsumptionEntry[] = [];
      public visible = false;
      constructor(http: Http) {
          http.get("assets/fuel/león_fuelings.csv").subscribe(
            csv => { this.leon = this.parse(csv); this.observable.next("León is there");this.visible=true;},
            error =>  this.errorMessage = <any>error);
      
      }
      
      <ngx-charts-line-chart
        *ngIf="visible"
        [results]="leon"
        ...
      >
      </ngx-charts-line-chart>
      
    1. The pie chart has a “doughnut” option. I suppose you can use this and draw several doughnut rings with different radius and the same coordinates.

  2. Hi,
    Where is the ngx css (/node_modules/@swimlane/ngx-charts/release/ngx-charts.css)?

    I have found index.css…

    If I’d like to custom link or node style (force directed graph), I need to work diretly with d3 and svg???

    1. Good question. I’ve quickly browsed through the project. It contains a couple of SCSS files. As usual with Angular, these files are in the same folder as their component. At runtime, they are encapsulated in the shadow DOM. So I guess you can override these CSS rules by defining new CSS rules in the component using ngx-charts. Normally, shadow DOM ensures that CSS rules are only applied locally in your component. You can fix this by adding /deep/, as described in the Angular documentation.

      If you want to modify the properties of the SVG files, such as using a different arrow, you may need to derive your own component from one of the standard components of ngx-charts. You can do a lot with HTML CSS, but I’m not sure if it’s powerful enough to modify every aspect of the SVG image.

    1. The difference between Angular2 and Angular4 is more or less negligible. You should be able to run the code with Angular4 without major problems. However, it’s possible that ngxcharts has one or two breaking changes, so I might update the examples soon.

  3. Hi all,
    I am enjoying the ng-charts. I had a issue come up regarding css and the styles mostly colors of
    the tree-map.
    Everything was fine until I added a new component that was a Form using
    “import { FormsModule, ReactiveFormsModule } from ‘@angular/forms’;”
    and “@import url(“https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css”);”
    Now my ngx-charts-tree-map color is all Blue.

    Does anyone know a simple fix for this?

    i tried importing the .css only for the form but it stays in memory and then efftects the
    treemap.

    TIA
    FxM

Leave a Reply

Your email address will not be published.