2012-02-09 7 views
7

Sto aggiungendo nodi a un grafico layout di forza in questo modo:Come aggiungere il nodo composto in un layout forza D3?

var node = vis.selectAll("circle.node") 
    .data(nodes) 
    .enter() 
    .append("circle") 
    .attr("class", "node") 
    .attr("cx", function(d) { return d.x; }) 
    .attr("cy", function(d) { return d.y; }) 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 
    .call(force.drag); 

C'è un modo per aggiungere elementi SVG composti come nodi? Cioè Voglio aggiungere un collegamento ipertestuale per ogni cerchio, quindi avrei bisogno di qualcosa di simile:

<a href="whatever.com"><circle ...></circle></a>

risposta

32

Creazione di un elemento "composto" è semplice come aggiungendo uno o più figli a un altro elemento. Nell'esempio, si desidera associare i dati a una selezione di elementi <a> e assegnare a ciascun <a> un singolo <circle> figlio.

Prima di tutto, è necessario selezionare "a.node" anziché "circle.node". Questo perché i collegamenti ipertestuali saranno gli elementi principali. Se non c'è un ovvio elemento genitore e vuoi semplicemente aggiungere più elementi per ogni dato, usa <g>, l'elemento del gruppo SVG.

Quindi, si desidera aggiungere un elemento <a> a ciascun nodo nella selezione di immissione. Questo crea i tuoi collegamenti ipertestuali. Dopo aver impostato gli attributi di ciascun collegamento ipertestuale, devi assegnargli un figlio <circle>. Semplice: basta chiamare lo .append("circle").

var node = vis.selectAll("a.node") 
    .data(nodes); 

// The entering selection: create the new <a> elements here. 
// These elements are automatically part of the update selection in "node". 
var nodeEnter = node.enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .call(force.drag); 

// Appends a new <circle> element to each element in nodeEnter. 
nodeEnter.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }) 

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

Ricordate che D3 opera principalmente sul selezioni di nodi. Quindi chiamare .append() nella voce di immissione significa che ciascun nodo nella selezione ottiene un nuovo figlio. Roba potente!

Un'ultima cosa: SVG ha its own <a> element, che è quello a cui mi riferivo sopra. Questo è diverso da quello HTML! In genere, si utilizzano solo elementi SVG con SVG e HTML con HTML.

Grazie a @mbostock per aver suggerito di chiarire la denominazione delle variabili.

+0

Anche se capisco perché questo funzioni per la creazione, non si interrompe per l'aggiornamento? Poiché append() unisce le selezioni di inserimento e aggiornamento, non aggiungerà una nuova cerchia ai vecchi nodi ogni volta che viene chiamato l'aggiornamento? –

+0

Ho aggiornato l'esempio per renderlo più chiaro. selection.append non * unisce * nessuna selezione, ma selection.enter(). append aggiunge automaticamente gli elementi alla selezione di aggiornamento. Il mio esempio originale aveva vis.selectAll (...) .data (...) .enter(). Append (...). Questo aggiunge solo elementi alla selezione in entrata, quindi nessun problema lì; il punto chiave è che inizialmente la selezione di inserimento contiene solo segnaposto per * nuovi * elementi che non esistono ancora. –

10

Risposta a Jason Davies (poiché StackOverflow limita la lunghezza dei commenti di risposta ...): Risposta eccellente. Attenzione però al metodo di concatenazione; in genere si desidera che node faccia riferimento all'elemento di ancoraggio esterno anziché all'elemento del cerchio interno. Così mi consiglia una piccola variazione:

var node = vis.selectAll("a.node") 
    .data(nodes) 
    .enter().append("a") 
    .attr("class", "node") 
    .attr("xlink:href", "http://whatever.com") 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 
    .call(force.drag); 

node.append("circle") 
    .attr("r", 5) 
    .style("fill", function(d) { return fill(d.group); }); 

Ho anche sostituito cx del cerchio e cy attributi con una trasformazione in elemento di ancoraggio che contiene; o uno funzionerà. Puoi trattare svg: un elemento come svg: g (entrambi sono contenitori), che è bello se vuoi aggiungere etichette in un secondo momento.

+0

Grazie! Ho modificato leggermente il primo esempio (rimosso 'var node =' poiché è ridondante e potenzialmente confuso come si fa notare).Il secondo esempio con le variabili è coerente con il tuo, anche se sono d'accordo che la trasformazione sia probabilmente più utile. –