Es gibt gleich ein dutzend JavaScript Bibliotheken die sich um die Generierung von Charts kümmern. In diesem Beispiel soll es exemplarisch um die Verwendung und Einbindung von vis.js gehen. Analog dazu lässt sich natürlich auch jede andere Bibliothek auf die gezeigte Art und Weise in ein Angular 2 Projekt integrieren
Wir initialisieren unser Projekt in diesem Beispiel mittels angular-cli (https://github.com/angular/angular-cli) welches uns viele alltägliche Aufgaben bei der Erstellung und Weiterentwicklung von Angular 2 Projekten erleichtert Zusätzlich fügen wir die Abhängigkeiten zu Bootstrap und vis.js unsrem Projekt hinzu
ng start ng-vis-demo cd ng-vis-demo npm install bootstrap –save npm install vis –save
Sowohl bootstrap (bootstrap.css) als auch vis (vis.js) stellen Dateien zur Verfügung die normalerweise in der index.html direkt über ein script/css Tag referenziert werden und somit global in der Anwendung zur Verfügung stehen. Bei der Verwendung von angular-cli kümmert sich der Buildprozess um derlei Aufgaben, wir müssen lediglich unsere zentralen Scripte und CSS-Files konfigurieren:
angular-cli.json
... "styles": [ "../node_modules/bootstrap/dist/css/bootstrap.min.css", "../node_modules/vis/dist/vis.min.css", "styles.css" ], "scripts": [ "../node_modules/vis/dist/vis.min.js" ], …
Für die Einbindung von nativen Bibliotheken wie vis.js dient nun eine entsprechende Direktive die sich um die Initialisierung und Verarbeitung des Graphen kümmert. Diese kann entweder manuell angelegt werden oder mittels „ng“ generiert und automatisch dem Modul bekannt gemacht werden (ng g directive vis3dgraph)
src/app/directives/vis3dgraph.directive.ts
import { Directive, ElementRef, Input } from '@angular/core'; declare var vis: any; const DEFAULT_OPTIONS = { width: '100%', height: '700px', style: 'surface', showPerspective: true, showGrid: true, showShadow: false, keepAspectRatio: true, verticalRatio: 0.5, xCenter: '50%', yCenter: '35%', cameraPosition: { horizontal: 1.0, vertical: 0.5, distance: 2.0 } }; @Directive({ selector: '[appVis3DGraph]' }) export class Vis3dGraphDirective { @Input() public data: any; private _graph; any; constructor(private _element: ElementRef) { } public createGraph() { let container = this._element.nativeElement; if (!this._graph) { this._graph = new vis.Graph3d(container, this._generateData(), DEFAULT_OPTIONS); } else { this._graph.setData(this._generateData()); this._graph.redraw(); } } private _generateData() { let data = []; this.data.forEach((xValue, x) => data.push(...xValue.map((yValue, y) => { return { x, y, z: yValue.value }; }))); return data; } }
Hier erstellen wir eine Direktive die wir später mit dem Selektor “appVis3DGraph“ in unserem Template verwenden werden. Die Daten für das zu generierende Chart erhält die Direktive über einen entsprechenden Input Parameter (@Input() data) Für die eigentliche Erzeugung des Graphen lassen wir uns das Container-Element der Direktive im Konstruktor injecten, dessen Attribut „nativeElement“ das konkrete HTML Element referenziert, welches wir vis.js als Container zur Verfügung stellen. Zusätzlich bereiten wir die übergebenen Daten noch im benötigten Format auf und setzen einige Optionen bevor wir mittels vis.Graph3d einen den Graphen durch vis.js rendern lassen.
Die Verwendung der Direktive erfolgt dann im Template einer unserer Komponenten über den oben gewählten Selektor und die Übergabe der Daten in den Input Parameter der Direktive:
src/app/app.component.html
<div appVis3DGraph [data]="data"></div>
Der Vollständigkeit halber hier noch der entsprechende Controller, der die Daten für den Graphen bereit stellt:
src/app/app.component.ts
import { Component, OnInit, ViewChild} from '@angular/core'; import {Vis3dGraphDirective} from './directives/vis3dgraph.directive' @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { public data:any[][]; @ViewChild(Vis3dGraphDirective) private _graph:Vis3dGraphDirective; public ngOnInit(){ this.data=new Array(6).fill(0).map(_ => new Array(6).fill(0).map(_ => {return {value: Math.floor(Math.random()*100)}})); } public updateData(){ this._graph.createGraph(); } }
Neben der Generierung einiger Zufallszahlen für das Beispiel lassen wir uns mittels „ViewChild“ die verwendete Instanz der Direktive injizieren um bei entsprechender User Interaktion ein neu Laden des Graphen zu veranlassen.
Das war es schon. Dieses Beisiel zeigt eindrucksvoll wie einfach es ist native Script Bibliotheken in einem Angular 2 Projekt zu integrieren. Vis.js diente hier nur als ein Beispiel und lässt im Bereich der Datenvisualisierung leider einige Funktionen vermissen: so besteht in LineCharts und 3DGraphen z.B. leider nicht die Möglichkeit einzelne Punkte zu selektieren. Bestehen solche Anforderungen lohnt möglicherweise ein Blick auf plotly.js, welches seit geraumer Zeit ebenfalls als OpenSource Variante zur Verfügung steht. Die Einbindung würde dann analog zu oben über eine Direktive geschehen.