pipou
pipou

Reputation: 370

mousemove event, access to this context

Fisrt of all I'm using D3js inside a React component so I use some variable of my class to save datas e.g.: this.graphicalId = 'test';

I have two items in my d3 element, svgViewport which is a g element and streams which are path elements. I have .on('mousemove' event handle for each.

In the streams event I would like save the name of the current stream using d3.select(this) (note I'm in a function() and not an arrow function so this is local) in a global variable in order to use it in the svgViewport event.

My problem is that like I'm in a function() this is local and not link to my class instance so I can't save the value in a member variable this.currentStreamName.

A bit of code :

svgViewport.on('mousemove', function (d, i) {
    if (mouseIsOverStream) {
        let mousex = d3.mouse(this);
        mousex = mousex[0];
        // here I want this of the class instance context
        this.nearestTickPosition, this.currentStreamName = findNearestTickPosition(mousex);
    }
});

Do you have some advices to deal with it ?

Thanks.

Upvotes: 2

Views: 164

Answers (2)

altocumulus
altocumulus

Reputation: 21578

You can use arrow functions to get access to the instance's this context and still acquire the current DOM element. For the DOM element you resort to the little-known and often overlooked third parameter of the event listener. As the docs have it (emphasis mine):

the specified listener will be evaluated for the element, being passed the current datum (d), the current index (i), and the current group (nodes)

Since the current index i is the pointer into the current group nodes you can refer to the current DOM element as nodes[i].

Your code thus becomes:

svgViewport.on('mousemove', (d, i, nodes) => {
    if (mouseIsOverStream) {
        let mousex = d3.mouse(nodes[i]);  // get the current element as nodes[i]
        mousex = mousex[0];
        // this now refers to your instance
        this.nearestTickPosition, this.currentStreamName = findNearestTickPosition(mousex);
    }
});

Upvotes: 1

gugadev
gugadev

Reputation: 202

Store the class context in a variable out of the event binding. Then, make an IIFE and bind it's context to the stored one.

componentDidMount() {
  const ctx = this;
  svgViewport.on('mousemove', function (d, i) {
    if (mouseIsOverStream) {
      let mousex = d3.mouse(this);
      mousex = mousex[0];
      !function () {
        // here I want this of the class instance context
        this.nearestTickPosition, this.currentStreamName = findNearestTickPosition(mousex);
      }.bind(ctx)();
    }
  });
}

Also, this should work too:

componentDidMount() {
  svgViewport = ...;
  svgViewport.on('mousemove', (d, i) => {
    if (mouseIsOverStream) {
      let mousex = d3.mouse(svgViewport); // here
      mousex = mousex[0];
      this.nearestTickPosition, this.currentStreamName = findNearestTickPosition(mousex);
    }
  });
}

Upvotes: 1

Related Questions