javascript - quimicos - estructura de lewis
Resalte el nodo seleccionado, sus enlaces y sus hijos en un gráfico dirigido por fuerza D3 (1)
Estoy trabajando en un gráfico de fuerza dirigida en D3. Quiero resaltar el nodo mouseover''d, sus enlaces y sus nodos secundarios al establecer todos los otros nodos y enlaces a una opacidad menor.
En este ejemplo, http://jsfiddle.net/xReHA/ , puedo desvanecer todos los enlaces y nodos y luego desvanecerme en los enlaces conectados, pero, hasta ahora, no he podido desvanecerme elegantemente en el nodos conectados que son hijos del nodo con mouseover actualmente.
Esta es la función clave del código:
function fade(opacity) {
return function(d, i) {
//fade all elements
svg.selectAll("circle, line").style("opacity", opacity);
var associated_links = svg.selectAll("line").filter(function(d) {
return d.source.index == i || d.target.index == i;
}).each(function(dLink, iLink) {
//unfade links and nodes connected to the current node
d3.select(this).style("opacity", 1);
//THE FOLLOWING CAUSES: Uncaught TypeError: Cannot call method ''setProperty'' of undefined
d3.select(dLink.source).style("opacity", 1);
d3.select(dLink.target).style("opacity", 1);
});
};
}
Uncaught TypeError: Cannot call method ''setProperty'' of undefined
un Uncaught TypeError: Cannot call method ''setProperty'' of undefined
error Uncaught TypeError: Cannot call method ''setProperty'' of undefined
cuando intento establecer la opacidad en un elemento que cargué desde el source.target. Sospecho que esta no es la forma correcta de cargar ese nodo como un objeto d3, pero no puedo encontrar otra manera de cargarlo sin iterar sobre todos los nodos nuevamente para encontrar los que coinciden con el destino o fuente del enlace. Para mantener el rendimiento razonable, no quiero iterar sobre todos los nodos más de lo necesario.
Tomé el ejemplo de desvanecer los enlaces de http://mbostock.github.com/d3/ex/chord.html :
Sin embargo, eso no muestra cómo alterar los nodos secundarios conectados.
Cualquier buena sugerencia sobre cómo resolver o mejorar esto será votada furiosamente :)
El error se debe a que está seleccionando los objetos de datos (d.source y d.target) en lugar de los elementos DOM asociados con esos objetos de datos.
Tienes la línea resaltada funcionando, pero probablemente combinaría tu código en una sola iteración, como esta:
link.style("opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity;
});
Resaltar los nodos vecinos es más difícil porque lo que necesita saber los vecinos para cada nodo. Esta información no es tan fácil de determinar con sus estructuras de datos actuales, ya que todo lo que tiene es una matriz de nodos y una matriz de enlaces. Olvídese del DOM por un segundo, y pregúntese cómo determinaría si dos nodos b
son vecinos.
function neighboring(a, b) {
// ???
}
Una forma costosa de hacerlo es iterar sobre todos los enlaces y ver si hay un enlace que conecta ayb:
function neighboring(a, b) {
return links.some(function(d) {
return (d.source === a && d.target === b)
|| (d.source === b && d.target === a);
});
}
(Esto supone que los enlaces no están dirigidos. Si solo desea resaltar los vecinos conectados hacia adelante, entonces elimine la segunda mitad del O).
Una forma más eficiente de calcular esto, si tiene que hacerlo con frecuencia, es tener un mapa o una matriz que permita la búsqueda de tiempo constante para probar si a y b son vecinos. Por ejemplo:
var linkedByIndex = {};
links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
Ahora puedes decir:
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
Y así, ahora puede iterar sobre los nodos y actualizar su opacidad correctamente:
node.style("opacity", function(o) {
return neighboring(d, o) ? 1 : opacity;
});
(También es posible que desee linkedByIndex
un caso especial en el enlace en sí, estableciendo un enlace automático para cada nodo en linkedByIndex
, o probando d
directamente cuando se calcula el estilo, o usando un estilo! Css :hover
.! Important).
Lo último que cambiaría en su código es usar opacidad de relleno y opacidad de trazo en lugar de opacidad, ya que ofrecen un rendimiento mucho mejor.