Estoy construyendo una red con d3js (básicamente nodos y enlaces)
Cuando paso el mouse sobre un nodo, quiero resaltar los enlaces asociados y colocarlos en la parte superior de parentNode para que sean realmente visibles.
Al pasar el mouse, hice algo como esto
// get links to highlight given the selected node var highlightLinks = nodeLinks(id); lines.each(function(index){ // if index is in selected links if (highlightLinks.include(index)){ // highlight link with yellow color this.setAttribute('style',"stroke:#ffc900") // raise the link on top of parent node d3.select(this).raise() } else { // else grey this.setAttribute('style',"stroke:#1B1B1B") } }Está funcionando bien con el primer mouseouver. Pero cuando salgo, mis líneas ya no están ordenadas de la misma manera, y la cláusula if resalta enlaces aleatorios para otros mouseovers
Creo que la solución debería ser volver a ordenar los enlaces al salir del mouseover, pero no puedo encontrar la manera de hacerlo. He almacenado el movedIndex como una matriz
Lo que me gustaría:
[0,1,2,3,4,5]movedIndex = [1,2][0,3,4,5,1,2]movedIndex para "desencauzarlos"[0,1,2,3,4,5]Llamar d3.lower() en orden inverso restaurará el orden original después de d3.raise() . Ver reorderItems como un ejemplo:
const colors = ['red', 'green', 'blue', 'yellow', 'orange']; const g = d3.select('g'); const angleUnit = Math.PI * 2 / colors.length; const reorderItems = () => { for (let index = colors.length - 1; index >= 0; index--) g.select(`circle[item-index='${index}']`).lower(); } const createItem = (color, index) => { const angle = angleUnit * index; const x = 50 * Math.sin(angle); const y = 50 * -Math.cos(angle); g.append('circle') .attr('cx', x) .attr('cy', y) .attr('r', 40) .attr('item-index', index) .style('fill', color) .on('mouseenter', function() { d3.select(this).raise(); }) .on('mouseleave', reorderItems); } colors.forEach(createItem); <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg width="200" height="200"> <g transform="translate(100, 100)" /> </svg>Siempre que no cambie sus datos, la alternativa más sencilla es selection.order() , que:
Vuelve a insertar elementos en el documento de modo que el orden del documento de cada grupo coincida con el orden de selección.
Por lo tanto, todo lo que necesita en su evento mouseout es esto:
lines.order();Aquí hay una demostración simple (usando v7):
const svg = d3.select("svg"); const circles = svg.selectAll(null) .data(d3.range(0, 1.2, 0.2)) .enter() .append("circle") .attr("r", 40) .attr("cy", 50) .attr("cx", d => 80 + 240 * d) .style("fill", d3.interpolateTurbo); circles.on("mouseover", event => d3.select(event.currentTarget).raise()) .on("mouseout", () => circles.order()); <script src="https://d3js.org/d3.v7.min.js"></script> <svg width="400" height="100"></svg>