javascript - D3 Separación del diseño del árbol entre nodos usando NodeSize
tree d3.js (3)
En este momento estoy tratando de separar mis nodos rectangulares porque se superponen como se muestra en la imagen siguiente:
nodeSize un vistazo y descubrí que D3 ofrece un método de separation y nodeSize , pero por alguna razón no funcionó.
Encontré esta publicación de blog hablando sobre el tema, pero él dice
La propiedad de tamaño no existe en los nodos, por lo que será cualquier propiedad que desee controlar el tamaño de ellos.
pero claramente hay un método nodeSize así que siento que simplemente estoy usando el método incorrectamente y / o la publicación del blog está desactualizada. Quiero dar forma a mis nodos para que sean del tamaño del rectángulo y espaciarlos de manera uniforme para que no se superpongan entre sí. ¿Alguien sabe cómo usar los métodos correctamente? La documentación sobre estos métodos no se explica muy bien y no está produciendo ninguna diferencia. Tampoco pude encontrar muchos ejemplos en los que la gente cambiara el nodo Tamaño de los árboles o la separación necesaria para los objetos rectangulares (había algunos ejemplos con respecto a los circulares, pero creo que eso es demasiado diferente ...)
Aquí está el código relevante. Trataré de preparar 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 d.x, d.y
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 + ")");
No entendí bien la respuesta aceptada hasta que hice algunas excavaciones propias, así que pensé en compartir lo que encontré también ...
Si está utilizando .size()
y sus nodos se superponen, utilice .nodeSize()
lugar
Como se explica en la respuesta aceptada, .size()
establece el tamaño disponible del árbol, por lo que, dependiendo del espacio entre los nodos primos, los primos segundos, etc., se pueden agrupar y superponer. El uso de .nodeSize()
simplemente dice que cada nodo debe obtener este espacio, ¡por lo que nunca se superpondrán!
El código que terminó trabajando para mí fue
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;
});
Sin horizontalSeparationBetweenNodes
y verticalSeparationBetweenNodes
los bordes de los nodos se tocaban entre sí. También agregué .separation()
para disminuir la cantidad de espacio entre los nodos primos, ya que mis nodos son bastante anchos y se desperdicia mucho espacio.
Nota: Esto es para d3 v3, no v4
Primero, gracias a todos los que publicaron antes, oro puro. Quería agregar a esta publicación para aquellos que podrían estar luchando con el problema de compensación asociado con un árbol dibujado horizontalmente.
La clave es que si cambia de .size () a .nodeSize () en un árbol horizontal, notará que su nodo raíz parece saltar / reorientarse para ubicarse en (0,0). Y según la documentación de d3.js, este es realmente el caso (ver https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize )
Sin embargo, para ajustarlo solo necesita asegurarse de reorientar su viewBox
. Es decir, cuando .append
tu svg
necesitas configurar explícitamente tu viewBox
. Aquí está mi pequeña línea hacky donde funcionó para mí ...
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 + ")");
ACTUALIZACIÓN 05/04/2018 : Entiendo que d3 ha cambiado mucho (para mejor) para ser mucho más modular. Para aquellos que están buscando esta respuesta, esto estaba usando una versión mucho más antigua de d3 (específicamente v3).
Muchos de los hallazgos siguen siendo relevantes para el paquete d3-hierarchy
en cluster.size()
y cluster.nodeSize()
y estoy planificando la posibilidad de actualizar mi ejemplo para usarlo. Sin embargo, para referencia histórica, estoy dejando el fondo intacto.
Aquí hay un jsFiddle: http://jsfiddle.net/augburto/YMa2y/
EDITAR: actualizado y mover el ejemplo a Codepen. El ejemplo todavía existe en jsFiddle pero Codepen parece tener un editor más agradable y te permite bifurcar fácilmente. También intentaré agregar el ejemplo directamente a esta respuesta una vez que haya reducido la cantidad de contenido en ella.
http://codepen.io/augbog/pen/LEXZKK
Actualizando esta respuesta. Hablé con mi amigo y miramos la fuente de size
y 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;
};
Cuando establece un size
para el árbol, está configurando un tamaño fijo para que el árbol se ajuste a ese ancho y alto. Cuando configura un nodeSize
, el árbol debe ser dinámico para que restablezca el tamaño del árbol.
Cuando especifiqué el size
después de nodeSize
, estaba sobrepasando lo que quería jaja ...
En nodeSize
: si desea que nodeSize
funcione, no puede tener un tamaño de árbol fijo. Establecerá el tamaño en null
. No declare un size
si declara un size
nodeSize
.
EDITAR: D3.js realmente actualizó la documentación . ¡Gracias a quien hizo eso porque ahora está más claro!
La propiedad nodeSize es exclusiva con tree.size; setting tree.nodeSize establece tree.size en null.
Así es como se ve mi árbol ahora. También agregué la funcionalidad de zoom y la forma de centrar el texto dentro del rectángulo.