Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript/D3 v4 - Context of this in d3.drag().on("end", this.dragended)

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(d3.drag()
    .on("start", this.dragstarted)
    .on("drag", this.dragged)
    .on("end", this.dragended)
);

These are the functions I call when the dragging starts, is going on and ends.

dragended(d: TCMemberScenario, i: number) {
    d3.select(this).classed("active", false);
    d.calculateRoles();
    this.save();
}

This is the function that is called when the dragging has ended. I update some things in the diagram and then I want to call the save method. This is another method in the class. However, the this variable is referencing to the D3 object and not the instance of the class. So I get a "Uncaught TypeError: Cannot read property 'save' of undefined"

How can I call from the dragended method another method of my class?

like image 724
Wybren Kortstra Avatar asked Aug 14 '16 18:08

Wybren Kortstra


2 Answers

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))
);
like image 90
Amid Avatar answered Nov 20 '22 06:11

Amid


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

like image 33
gabo bernal Avatar answered Nov 20 '22 06:11

gabo bernal