code d3.js ecmascript-6 arrow-functions

code - D3.js v4: Accede al elemento DOM actual en el detector de eventos de función de flecha ES6



svg append text (2)

En D3.js v4, cuando se registra un detector de eventos a través de una función de devolución de llamada tradicional, this referencia al elemento DOM actual:

d3.select("div").on(''mouseenter'', function() { d3.select(this).text("Yay"); });

ES6 ofrece funciones de flecha, que en mi humilde opinión hacen que el código D3.js sea mucho más legible porque es muy conciso. Sin embargo, las devoluciones de llamada tradicionales no se pueden reemplazar a ciegas con las funciones de flecha:

d3.select("div").on(''mouseenter'', () => { d3.select(this); // undefined });

El artículo " En D3 y funciones de flecha " ofrece una muy buena explicación de por qué this no está vinculado como se esperaba. El artículo sugiere utilizar devoluciones de llamada tradicionales para el código que necesita acceso al elemento DOM actual.

¿Es posible acceder al elemento DOM actual desde una función de flecha ?


Es posible utilizar una función de flecha ES6 y acceder al elemento DOM actual a través de d3.event.target :

d3.select("div").on(''mouseenter'', () => { d3.select(d3.event.target).text("Yay, this works!"); });


Hay una forma idiomática de hacer esto en D3: simplemente usa el tercer argumento menos famoso:

selection.on("mouseenter", (d, i, nodes) => { d3.select(nodes[i]); });

Y eso es lo mismo de:

selection.on("mouseenter", function() { d3.select(this); });

Escribí un ejemplo aquí: d3 v4 recupera el destino DOM de drag desde la devolución de llamada al arrastrar cuando `this` no está disponible

Aquí hay una demostración:

d3.selectAll("circle").on("mouseover", (d, i, p) => { d3.select(p[i]).attr("fill", "maroon") }) .on("mouseout", (d, i, p) => { d3.select(p[i]).attr("fill", "seagreen") });

<script src="https://d3js.org/d3.v4.min.js"></script> <svg> <circle cx="50" cy="50" r="20" fill="seagreen"></circle> <circle cx="125" cy="50" r="20" fill="seagreen"></circle> <circle cx="200" cy="50" r="20" fill="seagreen"></circle> </svg>

En realidad, si mira el final del artículo que ha vinculado, le da la misma solución.

La solución propuesta , d3.event.target , a pesar de trabajar para oyentes de eventos, no funciona en varias situaciones. Por ejemplo:

d3.selectAll("circle").each(()=>d3.select(d3.event.target).attr("fill", "red"))

<script src="https://d3js.org/d3.v4.min.js"></script> <svg> <circle cx="50" cy="50" r="20" fill="seagreen"></circle> <circle cx="125" cy="50" r="20" fill="seagreen"></circle> <circle cx="200" cy="50" r="20" fill="seagreen"></circle> </svg>

Pero el mismo código funciona usando el tercer argumento:

d3.selectAll("circle").each((d,i,p)=>d3.select(p[i]).attr("fill", "red"))

<script src="https://d3js.org/d3.v4.min.js"></script> <svg> <circle cx="50" cy="50" r="20" fill="seagreen"></circle> <circle cx="125" cy="50" r="20" fill="seagreen"></circle> <circle cx="200" cy="50" r="20" fill="seagreen"></circle> </svg>