如何在角度与D3中使用'this'?

时间:2017-09-25 13:17:59

标签: javascript angular d3.js svg

Tldr;当Angular将this绑定到类(组件/服务)时,如何处理this引用D3对象?

我希望在Angular(v.4)应用中使用D3.js(v.4)。

我的代码在独立的JavaScript中运行,但我现在需要将它集成到Angular应用程序中。

使用this让我感到沮丧。

我有一个我希望拖动的SVG组,因此我使用.call(drag)

someFunction() {
    this.unitGroup = this.svg.append('g')
            .attr('id', 'unitGroup');
            .call(drag)

}

当我尝试引用被拖动的svg元素时,我的问题就出现了。在我的原始代码中,我可以参考this,例如let matrix = this.getCTM()。在服务中使用此代码时,使用this现在无效。

drag = d3.drag()
    .on('start', () => {
        this.setClickOrigin(d3.event);
    })
    .on('drag', (d) => {
        const m = this.getCTM(); // <--- PROBLEM HERE
        const x = d3.event.x - this.clickOrigin.x;
        const y = d3.event.y - this.clickOrigin.y;
        this.setClickOrigin(d3.event);
        d3.select(this) // <--- PROBLEM HERE
            .attr('transform', `matrix(${m.a},${m.b},${m.c},${m.d},${m.e + x},${m.f + y})`);
    });

关于如何实现这一点或澄清我做错的任何指示都将不胜感激。

我认为这不仅仅是与箭头函数this绑定相关的错误,因为.on('drag', function(d){...}会导致相同的错误。

以下是Plunker说明我的问题:https://embed.plnkr.co/p1hdhMBnaebVPB6EuDdj/

2 个答案:

答案 0 :(得分:8)

在大多数D3方法中,this指的是DOM元素,它是获取元素的最简单方法。但是,您在角度代码中使用this时遇到了一些问题。

好消息是,有一种惯用方式可以在不依赖this的情况下获取当前DOM元素(并且不依赖d3.event):使用第二个第三个​​参数组合在一起。这在您无法使用this的情况下非常有用,例如您现在的状况或使用箭头功能时。

API上广泛记录了this的替代方案。对于大多数D3方法,您可以读到该方法是......

  

...传递当前数据(d),当前索引(i)和当前组(节点), this 作为当前DOM元素( nodes [ I] )。 (两者都强调我的)

因此,在常见的D3代码中,您可以使用以下命令获取DOM元素:

.on("whatever", function(){
    d3.select(this).etc...
//              ^--- 'this' is the DOM element

或者:

.on("whatever", function(d,i,n){
//                         ^-^--- second and third arguments
    d3.select(n[i]).etc...
//              ^--- here, 'n[i]' is also the DOM element

因此,在您的情况下,只需使用:

.on('drag', (d,i,n) => {
    const m = d3.select(n[i]).node().getCTM();
//the same of 'this'-----^
...
}

由于d3.select(n[i])选择,您必须使用node()来获取实际的DOM元素。

这是您更新的plunker:https://plnkr.co/edit/tjQ6lV411vAUcEKPh0ru?p=preview

答案 1 :(得分:3)

尝试使用d3.event.sourceEvent.target

.on('drag', () => {
  const target = d3.event.sourceEvent.target;
  const m = target.getCTM();
  const x = d3.event.x - this.clickOrigin.x;
  const y = d3.event.y - this.clickOrigin.y;
  this.setClickOrigin(d3.event);
  d3.select(target)

<强> Forked Plunker Example