I am using the D3 library to move an item within a Venn-diagram. When I stop dragging I want to determine the position of the item in the diagram.
item.call(
If you need to keep the reference to the class instance and also the element instance referenced by d3 drag you can define your listener functions as:
export class MyClass {
@Input()
radius: number = 45;
constructor() {
d3.drag()
.on("start", this.dragStarted(this))
.on("drag", this.dragged(this))
.on("end", this.dragEnded(this));
}
private dragged(self) {
return function(d) {
// 'this' in this context will be the d3 element
d3.select(this)
.attr("cx", d.x = self.radius * Math.cos(alpha))
.attr("cy", d.y = d3.event.y < 0 ? -self.radius * Math.sin(alpha) : self.radius * Math.sin(alpha));
}
}
...
}
Tested with d3.js v4
As a matter of principle, D3 binds the this
context of callbacks on selections, transitions and the like to the DOM element on which they operate.
By implication, if you need to access the this
context of a "wrapping object" in a lexical scope sense, you cannot use this
to access it. Applied to your specific case:
d3.select(this)
will operate on the currently iterated DOM element which will have the type of the DOM element underlying the item
selection. So, if your item
is e.g. of type SVGCircleElement
, such will be the this
context of your dragended
function.this
context as well is by creating a closure around the dragended
function:You can add a private method to your wrapping object which has the save
method:
private getDragEndedHandler() {
let self = this; // object context to preserve
return function(d: TCMemberScenario, i: number) {
d3.select(this).classed("active", false); // D3 bound DOM element context
d.calculateRoles();
self.save(); // closure-preserved object context
}
}
Now, when you bind the handler event, you simply do the following:
item.call(d3.drag()
.on("start", this.dragstarted)
.on("drag", this.dragged)
.on("end", this.getDragEndedHandler())
);
The same pattern can be applied to the other event handlers if need be.
If you use the latest definitions for d3-selection
and d3-drag
from npm @types, you will see that they now have generics to be more explicit about the this
context typing pertaining to DOM elements and D3 callbacks.
To keep reference to 'this' use arrow functions like this:
item.call(d3.drag()
.on("start", (d, i) => this.dragstarted(d,i))
.on("drag", (d, i) => this.dragged(d, i))
.on("end", (d, i) => this.dragended(d, i))
);