2012-01-05 13 views
66

Sto lavorando a un grafico di forza diretta in D3. Voglio evidenziare il nodo mouseover, i suoi collegamenti e i suoi nodi figli impostando tutti gli altri nodi e collegamenti su un'opacità inferiore.Evidenzia il nodo selezionato, i relativi collegamenti e i relativi elementi secondari in un grafico diretto forzato D3

In questo esempio, http://jsfiddle.net/xReHA/, sono in grado di sfumare tutti i collegamenti e i nodi e quindi dissolvenza nei collegamenti collegati, ma, finora, non sono stato in grado di svanire elegantemente nei nodi collegati che sono bambini del nodo attualmente mouseover.

Questa è la funzione chiave dal codice:

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); 
     }); 
    }; 
} 

sto ottenendo un errore di Uncaught TypeError: Cannot call method 'setProperty' of undefined quando cerco di impostare l'opacità su un elemento ho caricato dal source.target. Sospetto che questo non sia il modo giusto per caricare quel nodo come oggetto d3, ma non riesco a trovare un altro modo per caricarlo senza iterare nuovamente su tutti i nodi per trovare quelli che corrispondono alla destinazione o alla sorgente del link. Per mantenere le prestazioni ragionevoli, non voglio scorrere tutti i nodi più del necessario.

ho preso l'esempio di dissolvenza i link da http://mbostock.github.com/d3/ex/chord.html:

enter image description here

Tuttavia, che non mostra come modificare i nodi figlio collegati.

Eventuali buoni suggerimenti su come risolvere o migliorare questo sarà furiosamente upvoted :)

risposta

86

L'errore è dovuto al fatto che si sta selezionando gli oggetti di dati (d.source e d.target) piuttosto che gli elementi DOM associati quegli oggetti dati.

Hai la linea di evidenziazione di lavoro, ma avrei probabilmente combinare il codice in una singola iterazione, in questo modo:

link.style("opacity", function(o) { 
    return o.source === d || o.target === d ? 1 : opacity; 
}); 

Evidenziando i nodi vicini è più difficile perché ciò che è necessario conoscere i vicini per ogni nodo. Questa informazione non è così facile da determinare con le strutture dati attuali, dal momento che tutto ciò che hai come una serie di nodi e una serie di collegamenti. Dimentica il DOM per un secondo e chiediti come valuteresti se due nodi a e b sono vicini di casa?

function neighboring(a, b) { 
    // ??? 
} 

un modo costoso per farlo è quello di iterare su tutti i link e vedere se c'è un link che collega A e B:.

function neighboring(a, b) { 
    return links.some(function(d) { 
    return (d.source === a && d.target === b) 
     || (d.source === b && d.target === a); 
    }); 
} 

(Questo presuppone che i collegamenti siano undirected Se vuoi solo evidenziare i vicini connessi in avanti, quindi eliminare la seconda metà dell'OR.)

Un modo più efficiente di calcolare questo, se devi farlo frequentemente, è avere una mappa o una matrice che permetta ricerca a tempo costante per verificare se a e b sono vicini.Per esempio:

var linkedByIndex = {}; 
links.forEach(function(d) { 
    linkedByIndex[d.source.index + "," + d.target.index] = 1; 
}); 

Ora si può dire:

function neighboring(a, b) { 
    return linkedByIndex[a.index + "," + b.index]; 
} 

E così, è ora possibile scorrere i nodi e aggiornare la loro opacità correttamente:

node.style("opacity", function(o) { 
    return neighboring(d, o) ? 1 : opacity; 
}); 

(si potrebbe anche voler a caso speciale il collegamento mouseovered, sia impostando un collegamento automatico per ogni nodo in linkedByIndex, sia testando per d direttamente quando si calcola lo stile, o usando uno stile importante css :hover.)

L'ultima cosa che cambierei nel codice è usare opacità di riempimento e opacità del tratto piuttosto che opacità, perché offrono prestazioni molto migliori.

+1

Che funziona alla grande @mbostock, grazie mille: D Ho aggiornato [il jsfiddle] (http://jsfiddle.net/xReHA/1/) con la tua soluzione. –

+1

Rimossa una chiamata non necessaria allo stile sul collegamento: http://jsfiddle.net/xReHA/2/ –

+0

Mike, quella soluzione era semplicemente bellissima. Basta dire. – Vivek

Problemi correlati