web-dev-qa-db-ja.com

Angular 2でD3.jsを使用する

Angular 2(Alpha 44)をD3.jsと正常に統合しました。

<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);

すべてが正常に動作しています。ただし、ElementRefのAngular 2ドキュメントには次のように記載されています。

DOMへの直接アクセスが必要な場合、このAPIを最後の手段として使用します。代わりにAngularが提供するテンプレートとデータバインディングを使用してください。あるいは、ネイティブ要素への直接アクセスがサポートされていない場合でも安全に使用できるAPIを提供する{@link Renderer}をご覧ください。直接DOMアクセスに依存すると、アプリケーションとレンダリングレイヤーの間に緊密な結合が作成されるため、2つを分離してアプリケーションをWebワーカーにデプロイすることができなくなります。

ここで、D3.jsをRenderer APIに統合する方法について疑問が生じます。

75
Zia Khan

レンダラーを使用するには、未加工のHTML要素(nativeElement)が必要です。したがって、基本的には、ライブラリが何であれ、生の要素を取得してRendererに渡す必要があります。

例えば

// 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');

ElementRefに関する警告は、それを直接使用することに関するものです。これは推奨されないことを意味します

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

しかし、これは結構です

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

目的を示すために、jQueryでも使用できます

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

ただし、angular2が提供するものを使用して、他のライブラリに依存せずに簡単にこれを行うことをお勧めします。

純粋なangle2では、2つの簡単な方法があります

  • ディレクティブを使用する
// 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 {}
  • ローカル変数でViewChildを使用する
@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');
    }
}

plnkr は、この回答で言及したすべてのケースを示しています。もちろん、要件は異なる場合がありますが、可能な場合はいつでもangle2を使用してください。

54
Eric Martinez

これを試して:

npm install [email protected] --save必要なバージョンを設定するため

npm install @types/[email protected] --saveまたはd3 4+が必要な場合は上位バージョン

そして、あなたのts do

import * as d3 from 'd3';

うまく動作するはずです

5
Pian0_M4n

ElementRefの使用に問題がありましたが、そのAPIが変更されたかどうかわかりません。そのため、ViewContainRefを使用してnativeElementを取得することになりました。

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");
    };
}
3
Hello Dave
npm install --save d3

package.jsonのd3バージョンを確認し、node_modulesでも確認してください。

次に、component.tsで、以下のようにインポートします

import * as d3 from 'd3';
3
user7803780