使用D3.js和Angular 2

80

我已经成功地将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文档指出:

当需要直接访问DOM时,将此API作为最后手段使用。 相反,使用Angular提供的模板和数据绑定。 或者您可以查看{@link Renderer},它提供了一个API,即使在不支持对原生元素的直接访问时也可以安全地使用。 依赖于直接DOM访问会创建你的应用程序和渲染层之间的紧密耦合,这将使得无法将两者分开并将您的应用程序部署到Web Worker中。

现在问题是如何将D3.js与Renderer API集成?


这有帮助吗?http://www.ng-newsletter.com/posts/d3-on-angular.html - user2081554
我也在尝试让D3与Angular 2一起工作。在上面的示例中,我可以看到您在index.html中引用了d3-script,但我看不到您如何在app.js中获取d3变量? - user2915962
8
请确保执行npm install d3命令后,运行postinstall,以便由tsd创建d3.d.ts文件,然后使用import * as d3 from 'd3/d3';进行导入。 - drew moore
这里有一个评论提到的视频:https://dev59.com/TpLea4cB1Zd3GeqP7t2y,非常有趣。 - Michael
1
@urosjarc - 这是Angular 1,它有一种非常不同的方法来完成这些事情。 - superluminary
另一个相关视频 https://skillsmatter.com/skillscasts/8434-using-d3-with-angular-2-by-aendrew-rininsland (如果时间紧迫,请跳到第19分钟) - Aurelio
4个回答

58

要使用Renderer,你需要原始的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提供的方法来轻松完成此操作,而不依赖其他库。

通过纯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
那么,以使用bootstrap的折叠插件为例,我可以说 jQuery(this.el.nativeElement).collapse('show'); 是实例化该插件的一种完全可接受的方式,对吗? - garethdn
我猜指令方法对于动态添加的h3不起作用,对吗?例如:http://plnkr.co/edit/U2lvYqtGvdf7kWoRg10N?p=preview - eko

6
请尝试以下操作:
使用npm install d3@3.5.36 --save以设置所需版本。
如果您想要d3 4+,则可以使用npm install @types/d3@3.5.36 --save或更高版本。
然后,在您的ts 中执行以下操作: import * as d3 from 'd3'; 这样就可以正常工作了。

使用最新的d3(v4)并基于Angular 2快速启动示例,我还需要在systemjs.config.js文件中添加'd3':'npm:d3'到映射和'd3': {main:'build/d3.js', defaultExtension:'js'}到包。 - Nikos Tsokos
嗨@Entrodus,你介意给我提供基于Quickstart的确切安装顺序吗?我尝试按照您提出的系统模块进行操作,但仍然卡住了(没有./build/d2.js,也没有./build文件夹)。 - Stéphane de Luca
@StéphanedeLuca:1.设置Angular快速入门> 2.安装d3和d3版本4.4.0的typings> 3.在system.config.js中添加了d3的地图和包指令> 4.在使用d3的Angular组件中导入d3> 5.胜利。 - Nikos Tsokos

4
npm install --save d3

请检查package.json中的d3版本,并在node_modules中进行确认。

然后,在component.ts中按照以下方式导入:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接