Verwenden von D3.js mit Angular 2

78

Ich habe Angular 2 (Alpha 44) erfolgreich in D3.js integriert:

<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>
  System.config({packages: {'app': {defaultExtension: 'js'}}});
  System.import('app/app');
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>

app.js:

/// <reference path="./../../typings/tsd.d.ts" />

import {Component, bootstrap, ElementRef} from 'angular2/angular2';

@Component({
  selector: 'my-app',
  template: '<h1>D3.js Integrated if background is yellow</h1>',
  providers: [ElementRef]
})
class AppComponent { 
  elementRef: ElementRef;

  constructor(elementRef: ElementRef) {
   this.elementRef = elementRef;
  }

afterViewInit(){
    console.log("afterViewInit() called");
    d3.select(this.elementRef.nativeElement).select("h1").style("background-color", "yellow");
  }
}
bootstrap(AppComponent);

Alles funktioniert gut. Die Angular 2-Dokumentation für ElementRef enthält jedoch Folgendes:

Verwenden Sie diese API als letzten Ausweg, wenn ein direkter Zugriff auf DOM erforderlich ist. Verwenden Sie stattdessen die von Angular bereitgestellten Vorlagen und Datenbindungen. Alternativ können Sie sich {@link Renderer} ansehen, das eine API bereitstellt, die auch dann sicher verwendet werden kann, wenn der direkte Zugriff auf native Elemente nicht unterstützt wird. Wenn Sie sich auf den direkten DOM-Zugriff verlassen, wird eine enge Kopplung zwischen Ihrer Anwendung und den Rendering-Ebenen hergestellt, die es unmöglich macht, die beiden zu trennen und Ihre Anwendung in einem Web-Worker bereitzustellen.

Nun stellt sich die Frage, wie D3.js in die Renderer-APIs integriert werden können.

Zia Khan
quelle
Ist das in irgendeiner Hilfe? ng-newsletter.com/posts/d3-on-angular.html
Ich versuche auch, D3 dazu zu bringen, mit Winkel 2 zu arbeiten. Im obigen Beispiel kann ich sehen, dass Sie auf das d3-Skript in Ihrer index.html verweisen, aber ich kann nicht sehen, wie Sie die d3-Variable erhalten in app.js?
user2915962
8
@ user2915962 - npm d3 installieren, stellen Sie sicher postLäufe und d3.d.ts von tsd erstellt wird, dannimport * as d3 from 'd3/d3';
zog moore
Es gibt ein Video, das in einem der Kommentare hier erwähnt wird: stackoverflow.com/q/34704148/2050479 , das ziemlich interessant ist
Michael
1
@urosjarc - Das ist Angular 1, das eine ganz andere Art hat, solche Dinge zu tun.
Superluminary

Antworten:

58

Um Renderer verwenden zu können, benötigen Sie das rohe HTML-Element (auch bekannt als nativeElement). Grundsätzlich müssen Sie also Ihre Bibliothek verwenden, das Rohelement abrufen und an Renderer übergeben.

Zum Beispiel

// h3[0][0] contains the raw element
var h3 = d3.select(this.el.nativeElement).select('h3');
this.renderer.setElementStyle(h3[0][0], 'background-color', 'blue');

In der Warnung zu ElementRef geht es darum, es direkt zu verwenden. Das bedeutet, dass davon abgeraten wird

elementRef.nativeElement.style.backgroundColor = 'blue';

Aber das ist in Ordnung

renderer.setElementStyle(elementRef.nativeElement, 'background-color', 'blue');

Zum Anzeigen können Sie es auch mit jQuery verwenden

// h2[0] contains the raw element
var h2 = jQuery(this.el.nativeElement).find('h2');
this.renderer.setElementStyle(h2[0], 'background-color', 'blue');

Meine Empfehlung ist jedoch, das zu verwenden, was Angular2 Ihnen bietet, um dies einfach zu tun, ohne von anderen Bibliotheken abhängig zu sein.

Mit pure angle2 haben Sie zwei einfache Möglichkeiten

  • Direktiven verwenden
// This directive would style all the H3 elements inside MyComp
@Directive({
    selector : 'h3',
    host : {
        '[style.background-color]' : "'blue'"
    }
})
class H3 {}

@Component({
    selector : 'my-comp',
    template : '<h3>some text</h3>',
    directives : [H3]
})
class MyComp {}
  • Verwenden von ViewChild mit lokalen Variablen
@Component({
    selector : 'my-comp',
    template : '<h3 #myH3>some text</h3>',
})
class MyComp {
    @ViewChild('myH3') myH3;
    ngAfterViewInit() {
        this.renderer.setElementStyle(this.myH3.nativeElement, 'background-color', 'blue');
    }
}

Hier ist ein Plnkr mit allen Fällen, die ich in dieser Antwort erwähnt habe. Ihre Anforderungen können natürlich abweichen, aber versuchen Sie, angular2 zu verwenden, wann immer Sie können.

Eric Martinez
quelle
2
Würde ich zu Recht sagen, dass jQuery(this.el.nativeElement).collapse('show');dies für das Beispiel der Verwendung des Kollaps-Plugins von Bootstrap eine durchaus akzeptable Methode ist, um das Plugin zu instanziieren?
Garethdn
Ich denke, der Direktivenansatz würde für dynamisch angehängte h3s nicht funktionieren, oder? Beispiel: plnkr.co/edit/U2lvYqtGvdf7kWoRg10N?p=preview
eko
6

Versuche dies:

npm install [email protected] --save um die benötigte Version einzustellen

npm install @types/[email protected] --save oder eine höhere Version, wenn Sie d3 4+ wollen

und dann in deinem tsdo

import * as d3 from 'd3';

Sollte gut funktionieren

Pian0_M4n
quelle
mit dem neuesten d3 (v4) und basierend auf eckig 2 schnellstart beispiel musste ich auch 'd3':'npm:d3'zu map und 'd3': {main:'build/d3.js', defaultExtension:'js'}zu paketen in systemjs.config.jsdatei hinzufügen .
Nikos Tsokos
Hallo @Entrodus, hast du etwas dagegen, mir die genaue Installationssequenz basierend auf Quickstart zu geben? Ich habe versucht, dem zu folgen, einschließlich des von Ihnen vorgeschlagenen Mods des Systems, aber ich stecke immer noch fest (kein ./build/d2.js, auch kein ./build Ordner).
Stéphane de Luca
@ StéphanedeLuca: 1. Richten Sie einen Winkel-Schnellstart ein> 2. Installieren Sie d3 und geben Sie t3 für d3 Version 4.4.0 ein> 3. Fügen Sie Map- und Paket-Direktiven für d3 in system.config.js hinzu d3> 5.Sieg.
Nikos Tsokos
4
npm install --save d3

Überprüfen Sie die d3-Version in package.json und auch in node_modules.

Importieren Sie es dann in der Datei component.ts wie folgt

import * as d3 from 'd3';

quelle
3

Ich hatte Probleme mit ElementRef. Ich bin mir nicht sicher, ob sich diese API geändert hat. Also habe ich ViewContainRef verwendet, um das nativeElement zu erhalten.

import {Component, ViewContainerRef, OnInit} from '@angular/core';
declare var d3:any;
@Component({
    selector: 'line-chart',
    directives: [],
    template: `<div class="sh-chart">chart</div>`
})
export class LineChart implements OnInit{
    elem ;
    constructor(private viewContainerRef:ViewContainerRef) {}
    ngOnInit(){
        this.elem = this.viewContainerRef.element.nativeElement;

        d3.select(this.elem).select("div").style("background-color", "yellow");
    };
}
Hallo Dave
quelle