Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using arrow functions with d3

Tags:

Is it possible? I am not sure, since d3 makes heavy use of this rebindings and this seems to conflict with ES6 spec.

For instance, the following works fine:

// Working fine
var data = [1,2,3]
var svg = d3.select('body').append('svg').attr('height', 500).attr('width', 500).style('background-color', 'orange');
var gs = svg.selectAll('g').data(data).enter();
gs.append('circle')
    .attr('cx', function () { return Math.random()*500; })
    .attr('cy', function () { return Math.random()*500; })
    .attr('r', function () { return Math.random()*100; })
    .each(function () { console.log(this); });  // this is bound to the current element in the enter selection

While the following does not work as expected (this is not bound to the current element in the enter selection but to Window object):

var data = [1,2,3]
var svg = d3.select('body').append('svg').attr('height', 500).attr('width', 500).style('background-color', 'blue');
var gs = svg.selectAll('g').data(data).enter();
gs.append('circle')
    .attr('cx', () => Math.random()*500)
    .attr('cy', () => Math.random()*500)
    .attr('r', () => Math.random()*100)
    .each(() => console.log(this)); // this is bound to Window object

Related fiddle here.

like image 916
jarandaf Avatar asked Oct 01 '15 06:10

jarandaf


People also ask

When should you not use arrow functions?

An arrow function doesn't have its own this value and the arguments object. Therefore, you should not use it as an event handler, a method of an object literal, a prototype method, or when you have a function that uses the arguments object.

Is it better to use arrow functions?

Arrow functions are best for callbacks or methods like map, reduce, or forEach. You can read more about scopes on MDN. On a fundamental level, arrow functions are simply incapable of binding a value of this different from the value of this in their scope.

Can you use arrow functions to create object methods?

Arrow functions cannot be used to write object methods because, as you have found, since arrow functions close over the this of the lexically enclosing context, the this within the arrow is the one that was current where you defined the object.

Why would you use an arrow function?

Arrow functions introduce concise body syntax, or implicit return. This allows the omission of the curly brackets and the return keyword. Implicit return is useful for creating succinct one-line operations in map , filter , and other common array methods.


2 Answers

If you are using d3v4, you can access the current DOM node like this:

gs.append('circle')
    .attr('cx', () => Math.random()*500)
    .attr('cy', () => Math.random()*500)
    .attr('r', () => Math.random()*100)
    .each((d, i, j) => console.log(j[i])); 
        // j is current group, i is current index
like image 61
wdickerson Avatar answered Sep 23 '22 16:09

wdickerson


You can use arrow functions if you don't need access to this of the current element.

Fallback to the old style functions for cases where you want to access this of the current element.

Or use explicit binding to allow your function (not arrow function) to access whatever object you want using .bind()

To avoid working with this you have the option of using d3 name or class selectors to conveniently access any element. e.g.:

var stuffINeed = svg.selectAll('.someClass');
like image 27
chriskelly Avatar answered Sep 20 '22 16:09

chriskelly