如何在带有 D3 的 Angular 中使用“this”?
Posted
技术标签:
【中文标题】如何在带有 D3 的 Angular 中使用“this”?【英文标题】:How to use 'this' in Angular with D3? 【发布时间】:2018-03-06 11:38:54 【问题描述】:Tldr;当 Angular 将 this
绑定到类(组件/服务)时,如何处理引用 D3 对象的 this
?
我希望在 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/
【问题讨论】:
What does "this" refer to in arrow functions in ES6?的可能重复 改成 on('drag', function (d) ... ) 并不能解决问题。 你能在 plunker 中重现它吗?您可以尝试将this
更改为drag
,例如d3.select(drag)
或者您正在寻找d3.event.currentTarget
而不是this
我会看看这样做的。由于需要大量代码,我起初犹豫不决,我希望有人能认出我的错误。
我想在 plunker 中看到它)这是我的 d3 示例 plnkr.co/edit/qM3qrk3swvalQFBh1Db1?p=preview
【参考方案1】:
在大多数 D3 方法中,this
指的是 DOM 元素,它是最简单的获取元素的方法。但是,您在 Angular 代码中使用 this
会遇到一些问题。
好消息是,有一种惯用方法可以在不依赖this
(也不依赖d3.event
)的情况下获取当前DOM元素:使用second 和 第三个 参数相结合。这在您无法使用this
的情况下非常有用,例如您现在的情况或使用箭头函数时。
this
的替代方案在 API 中有大量文档。对于大多数 D3 方法,您可以读到该方法是...
... 正在传递当前数据 (d)、当前索引 (i) 和当前组 (nodes),其中 this 作为当前 DOM 元素 (nodes[我])。 (两者都强调我的)
因此,在一个常见的 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 元素。
这是您更新的插件:https://plnkr.co/edit/tjQ6lV411vAUcEKPh0ru?p=preview
【讨论】:
太棒了!谢谢! Plunker 按预期工作。为了让它在我的代码中工作,我必须做一个小的调整来让一个打字错误通过——“元素”类型上不存在属性“getCTM”。 const m = d3.select(n[i] as any).node().getCTM(); 有趣。在我的AppComponent
中声明d3
时,如何在不声明this.d3
的情况下引用d3
?就我而言,我在 AppComponent 的 ngOnInit 上创建了画布,我似乎无法在不声明 this.d3
的情况下引用 d3
@MichaelArdan 抱歉,我不是 Angular 用户。
非常有帮助,谢谢this
- 以编程方式同时使用 angular 和 d3 真的很痛苦。
非常感谢!对于面积图,我也面临同样的问题,但这种方法解决了我的问题。【参考方案2】:
尝试使用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
【讨论】:
感谢您的解决方案!我已将@GerardoFurtado 的答案标记为已接受,因为它看起来更可靠。在您的解决方案中移动深灰色框时,事件有时会出现切换到较大的框然后移动它。 它解决了其中一个问题!我很感激你的帮助。下一个问题可获得的奖励积分:***.com/questions/46423055/…以上是关于如何在带有 D3 的 Angular 中使用“this”?的主要内容,如果未能解决你的问题,请参考以下文章
使用 D3 在 DOM 中动态添加/删除 Angular 组件