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/
答案 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 强>