d3.js - d3 v4 recupera el objetivo de arrastrar DOM desde la devolución de llamada de arrastre cuando `this` no está disponible
(1)
Use el segundo y el tercer argumento juntos para obtener
this
cuando
this
no esté disponible:
d3.drag().on(typename, function(d, i, n) {
//here, ''this'' is simply n[i]
})
Para una explicación detallada, eche un vistazo al siguiente artículo que escribí para tratar
this
en las funciones de flecha.
El problema es diferente al suyo, pero la explicación es la misma.
Aquí hay una demostración básica, intenta arrastrar un círculo y mira la consola:
var data = d3.range(5)
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 100);
var circle = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("cy", 50)
.attr("cx", function(d) {
return 50 + 50 * d
})
.attr("r", 10)
.attr("fill", "tan")
.attr("stroke", "black")
.call(d3.drag()
.on("start", function(d, i, n) {
console.log(JSON.stringify(n[i]))
}))
<script src="https://d3js.org/d3.v4.min.js"></script>
PD: estoy usando
JSON.stringify
en la selección D3 porque los fragmentos de pila se congelan si intentas console.log una selección D3.
Usando "esto" con una función de flecha
La mayoría de las funciones en D3.js aceptan una función anónima como argumento.
Los ejemplos comunes son
.attr
,
.style
,
.text
,
.on
y
.data
, pero la lista es mucho más grande que eso.
En tales casos, la función anónima se evalúa para cada elemento seleccionado, en orden, que se pasa:
-
El dato actual (
d
) -
El índice actual (
i
) -
El grupo actual (
nodes
) -
this
como el elemento DOM actual.
El dato, el índice y el grupo actual se pasan como argumentos, el famoso primer, segundo y tercer argumento en D3.js (cuyos parámetros se denominan tradicionalmente
d
,
i
y
p
en D3 v3.x).
Para usar
this
, sin embargo, uno no necesita usar ningún argumento:
.on("mouseover", function(){
d3.select(this);
});
El código anterior lo seleccionará cuando el mouse esté sobre el elemento. Compruébelo trabajando en este violín: https://jsfiddle.net/y5fwgopx/
La función de flecha
Como una nueva sintaxis de ES6, una función de flecha tiene una sintaxis más corta en comparación con la expresión de la función.
Sin embargo, para un programador de D3 que usa
this
constantemente, existe una trampa: una función de flecha no crea su propio contexto.
Eso significa que, en una función de flecha,
this
tiene su significado original del contexto circundante.
Esto puede ser útil en varias circunstancias, pero es un problema para un programador acostumbrado a usar
this
en D3.
Por ejemplo, usando el mismo ejemplo en el violín anterior, esto no funcionará:
.on("mouseover", ()=>{
d3.select(this);
});
Si lo duda, aquí está el violín: https://jsfiddle.net/tfxLsv9u/
Bueno, eso no es un gran problema: uno simplemente puede usar una expresión de función regular y anticuada cuando sea necesario. Pero, ¿qué pasa si quieres escribir todo tu código usando las funciones de flecha? ¿Es posible tener un código con funciones de flecha y aún así usarlo correctamente en D3?
Los argumentos segundo y tercero combinados
La respuesta es
sí
, porque
this
es lo mismo para los
nodes[i]
.
La sugerencia está realmente presente en toda la API D3, cuando describe esto:
... con
this
como el elemento DOM actual (nodes[i]
)
La explicación es simple: dado que los
nodes
son el grupo actual de elementos en el DOM e
i
es el índice de cada elemento, los
nodes[i]
refieren al elemento DOM actual en sí.
Es decir,
this
.
Por lo tanto, uno puede usar:
.on("mouseover", (d, i, nodes) => {
d3.select(nodes[i]);
});
Y aquí está el violín correspondiente: https://jsfiddle.net/2p2ux38s/
La documentación para d3.drag establece que el objetivo del elemento DOM del evento de arrastre estará disponible para la devolución de llamada:
Cuando se distribuye un evento específico, cada oyente será invocado con el mismo contexto y argumentos que selection.on oyentes: el dato actual d e índice i, con este contexto como el elemento DOM actual.
Pero mi devolución de llamada es una instancia de objeto y
this
apunta a ese objeto.
Entonces, necesito otra forma de acceder al elemento DOM actual que normalmente se pasa en
this
.
¿Cómo puedo hacerlo?