Использование D3.js с Angular 2

Я успешно интегрировал 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);

Все работает нормально. Но Angular 2 документация для ElementRef гласит следующее:

Используйте этот API в качестве последнего средства, когда необходим прямой доступ к DOM. Используйте шаблоны и привязку данных, предоставленные Angular. В качестве альтернативы вы можете взглянуть на {@link Renderer}, который предоставляет API, который можно безопасно использовать, даже если прямой доступ к собственным элементам не поддерживается. Опираясь на прямой доступ DOM создает плотную связь между вашим приложением и уровнями рендеринга, что делает невозможным разделение двух и развертывание вашего приложения в веб-работнике.

Теперь возникает вопрос, как интегрировать D3.js с API-интерфейсом Renderer?

Ответ 1

Чтобы использовать Renderer, вам нужен необработанный HTML-элемент (aka 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 позволяет вам сделать это легко, не зависимо от других библиотек.

С чистым angular2 у вас есть два простых способа

  • Использование директив
// 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 со всеми случаями, упомянутыми в этом ответе. Конечно, ваши требования могут отличаться, но старайтесь использовать angular2, когда можете.

Ответ 2

Попробуйте следующее:

npm install [email protected] --save, чтобы установить нужную версию

npm install @types/[email protected] --save или более высокую версию, если вы хотите d3 4 +

а затем в ts do

import * as d3 from 'd3';

Должно работать просто отлично

Ответ 3

У меня возникли проблемы с использованием 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");
    };
}

Ответ 4

npm install --save d3

проверьте версию d3 в package.json и проверьте ее в node_modules.

то в component.ts импортируйте его ниже

import * as d3 from 'd3';