D3 Struttura ad albero Separazione tra i nodes usando NodeSize

In questo momento sto cercando di separare i miei nodes rettangolari perché si sovrappongono come mostrato nella figura qui sotto:

inserisci la descrizione dell'immagine qui

Ho dato un’occhiata e ho scoperto che D3 offre un metodo nodeSize e separazione ma per qualche motivo non ha funzionato.

Ho trovato questo post sul blog che parlava del problema, ma lui dice

La proprietà size non esiste nei nodes, quindi sarà qualsiasi proprietà che si desidera controllare la loro dimensione.

ma chiaramente c’è un metodo nodeSize quindi mi sento come se stessi semplicemente usando il metodo in modo errato e / o il post del blog non è aggiornato. Voglio modellare i miei nodes affinché siano la dimensione del rettangolo e distanziarli uniformsmente in modo che non si sovrappongano l’un l’altro. Qualcuno sa come usare correttamente i metodi? La documentazione su questi metodi non è spiegata molto bene e non sta producendo alcuna differenza. Inoltre non sono riuscito a trovare molti esempi in cui le persone cambiassero il nodeSize degli alberi o la separazione necessaria per gli oggetti rettangolari (c’erano alcuni esempi relativi a quelli circolari ma ritengo che sia troppo diverso …)

Ecco il codice pertinente. Proverò a preparare un JSFiddle.

var margin = {top: 20, right: 120, bottom: 20, left: 120}, height = 960 - margin.right - margin.left, width = 800 - margin.top - margin.bottom, rectW = 70; rectH = 30; //bbox = NaN, maxTextLength = 0; var i = 0, duration = 750, root; //paths from each node drawn initially here //changed to dx, dy var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.x+rectW/2, d.y+rectH/2]; //.projection(function(d) { return [d.x+bbox.getBBox().width/2, d.y+bbox.getBBox().height/2]; }); var tree = d3.layout.tree() .nodeSize([30,70]) .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2); }) .size([width, height]); var svg = d3.select("body") .append("svg") .attr("height","100%").attr("width","100%") .call(d3.behavior.zoom().on("zoom", redraw)) .append("g") .attr("transform", "translate(" + margin.top + "," + margin.left + ")"); 

AGGIORNAMENTO 05/04/2018 : Credo che d3 sia cambiato molto (in meglio) per essere molto più modulare. Per coloro che stanno cercando questa risposta, questo stava usando una versione molto più vecchia di d3 (in particolare v3).

Molti dei risultati sono ancora rilevanti per il pacchetto d3-hierarchy in cluster.size() e cluster.nodeSize() e sto pensando di aggiornare potenzialmente il mio esempio per usarlo. Per riferimento storico però, sto lasciando intatto il fondo.


Ecco un jsFiddle: http://jsfiddle.net/augburto/YMa2y/

MODIFICA: aggiornato e sposta l’esempio in Codepen. L’esempio esiste ancora su jsFiddle ma Codepen sembra avere un editor più carino e ti consente di eseguire facilmente il fork. Cercherò anche di aggiungere l’esempio direttamente a questa risposta dopo aver ridotto la quantità di contenuti in essa contenuti.

http://codepen.io/augbog/pen/LEXZKK

Aggiornamento di questa risposta. Ho parlato con il mio amico e abbiamo esaminato l’origine per size e nodeSize

  tree.size = function(x) { if (!arguments.length) return nodeSize ? null : size; nodeSize = (size = x) == null; return tree; }; tree.nodeSize = function(x) { if (!arguments.length) return nodeSize ? size : null; nodeSize = (size = x) != null; return tree; }; 

Quando si imposta una size per l’albero, si imposta una dimensione fissa in modo che l’albero debba conformarsi a tale larghezza e altezza. Quando imposti un nodeSize , l’albero deve essere dinamico in modo da reimpostare la dimensione dell’albero.

Quando ho specificato la size dopo nodeSize , stavo praticamente ignorando quello che volevo haha ​​…

In nodeSize : se vuoi che nodeSize funzioni, non puoi avere una dimensione di albero fissa. Imposta la dimensione su null . Non dichiarare una size se stai dichiarando un nodeSize .

EDIT: D3.js ha effettivamente aggiornato la documentazione . Grazie a chiunque l’abbia fatto perché ora è molto più chiaro!

La proprietà nodeSize è esclusiva con tree.size; setting tree.nodeSize imposta tree.size su null.

Ecco come appare il mio albero ora. Ho anche aggiunto la funzionalità di zoom e come centrare il testo all’interno del rettangolo.

Immagine in cui nodeSize è impostato su larghezza di 100 e altezza di 30

Non ho capito bene la risposta accettata fino a quando non ho scavato una mia, quindi ho pensato di condividere quello che ho trovato …

Se si utilizza .size() e i nodes si sovrappongono, utilizzare invece .nodeSize()

Come spiegato nella risposta accettata, .size() imposta la dimensione disponibile dell’albero, e quindi in base alla spaziatura tra i nodes cugini, i secondi cugini, ecc. Possono essere schiacciati insieme e sovrapposti. L’uso di .nodeSize() dice semplicemente che ogni nodo dovrebbe avere molto spazio, quindi non si sovrapporranno mai!

Il codice che ha funzionato per me è stato

 var nodeWidth = 300; var nodeHeight = 75; var horizontalSeparationBetweenNodes = 16; var verticalSeparationBetweenNodes = 128; var tree = d3.layout.tree() .nodeSize([nodeWidth + horizontalSeparationBetweenNodes, nodeHeight + verticalSeparationBetweenNodes]) .separation(function(a, b) { return a.parent == b.parent ? 1 : 1.25; }); 

Senza horizontalSeparationBetweenNodes e verticalSeparationBetweenNodes i bordi dei nodes si toccavano. Ho anche aggiunto questo .separation() per diminuire la quantità di spazio tra i nodes del cugino, poiché i miei nodes sono piuttosto ampi e si spreca molto spazio.

Nota: Questo è per d3 v3, non v4

Primo, grazie a tutti quelli che hanno pubblicato prima, oro puro. Volevo aggiungere a questo post quelli che potrebbero essere in difficoltà con il problema di offset associato a un albero disegnato orizzontalmente.

La chiave è, se passi da .size () a .nodeSize () su un albero orizzontale, noterai che il tuo nodo radice sembra saltare / riorientare per trovarsi a (0,0). E secondo la documentazione di d3.js questo è in realtà il caso (vedi https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize )

Tuttavia, per regolarti devi solo fare in modo di riorientare il tuo viewBox . Vale a dire, quando si .append tuo svg è necessario impostare in modo esplicito il tuo viewBox . Ecco la mia piccola linea hacky in cui ha funzionato per me …

 svg = d3.select("#tree").append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + 0 + 0) .attr("viewBox", "0 "+(-1*(height-margin.top-margin.bottom)/2)+" "+width+" "+height) .append("g") .attr("transform", "translate(" + margin.left + "," + 0 + ")");