D3 séparation de L'arborescence entre les nœuds à L'aide de NodeSize

En ce moment, j'essaie de séparer mes nœuds rectangles car ils se chevauchent comme indiqué dans l'image ci-dessous:

entrez la description de l'image ici

J'ai jeté un coup d'oeil et j'ai découvert que D3 offre une méthode nodeSize et separation mais pour une raison quelconque, cela n'a pas fonctionné.

, j'ai trouvé ce blog parler de la question, mais, dit-il

La propriété size n'existe pas dans les nœuds, donc ce sera la propriété de laquelle vous voulez contrôler la taille ils.

Mais il existe clairement une méthode nodeSize, donc j'ai l'impression d'utiliser simplement la méthode de manière incorrecte et / ou le billet de blog est obsolète. Je veux façonner mes nœuds à la taille du rectangle et les espacer uniformément afin qu'ils ne se chevauchent pas. Quelqu'un sait-il comment utiliser les méthodes correctement? La documentation sur ces méthodes n'est pas très bien expliquée et ne donne aucune différence. Je n'ai pas non plus trouvé beaucoup d'exemples où les gens ont changé le nodeSize de arbres ou séparation nécessaire pour les objets rectangulaires (il y avait quelques exemples concernant les objets circulaires mais je pense que c'est trop différent...)

Voici le code pertinent. Je vais essayer de préparer 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 + ")");
30
demandé sur aug 2013-07-10 01:32:35

3 réponses

Mise à jour 05/04/2018: je crois comprendre que d3 a beaucoup changé (pour le mieux) pour être beaucoup plus modulaire. Pour ceux qui regardent vers cette réponse, cela utilisait une version beaucoup plus ancienne de d3 (en particulier v3).

Beaucoup de résultats sont toujours d'actualité pour l'd3-hierarchy package sous cluster.size() et cluster.nodeSize() et j'ai l'intention de potentiellement mettre à jour mon exemple pour l'utiliser. Pour référence historique cependant, je quitte le fond intact.


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

EDIT: mis à jour et déplacez L'exemple vers Codepen. L'exemple existe toujours sur jsFiddle mais Codepen semble avoir un éditeur plus agréable et vous permet de bifurquer facilement. Je vais également essayer d'ajouter l'exemple directement à cette réponse une fois que j'ai réduit la quantité de contenu.

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

Mise à jour de cette réponse. J'ai parlé avec mon ami et nous j'ai regardé la source pour size et 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;
  };

Lorsque vous définissez un size pour l'arbre, vous définissez une taille fixe de sorte que l'arbre doit se conformer à cette largeur et à cette hauteur. Lorsque vous définissez un nodeSize, l'arbre doit être dynamique afin de réinitialiser la taille de l'arbre.

Quand j'ai spécifié size après nodeSize, Je dépassais à peu près ce que je voulais haha...

Bottom line : Si vous voulez que nodeSize fonctionne, vous ne pouvez pas avoir une taille d'arbre fixe. Il définira la taille sur null. Ne déclarez pas un size si vous déclarez un nodeSize.

Modifier: D3.js en fait a mis à jour la documentation . Merci à celui qui a fait cela parce que c'est beaucoup plus clair maintenant!

La propriété nodeSize est exclusive avec tree.taille; la mise arbre.nodesize définit l'arbre.la taille à la valeur null.

Voici à quoi ressemble mon arbre maintenant. J'ai également ajouté la fonctionnalité de zoom ainsi que la façon de centrer le texte dans le rectangle.

Image où nodeSize est défini sur une largeur de 100 et une hauteur de 30

43
répondu aug 2018-05-04 17:43:17

Je n'ai pas tout à fait compris la réponse acceptée jusqu'à ce que je fasse quelques recherches, alors j'ai pensé partager ce que j'ai trouvé aussi...

Si vous utilisez .size() et que vos nœuds se chevauchent, utilisez .nodeSize() à la place

Comme expliqué dans la réponse acceptée, .size() définit la taille disponible de l'arbre, et donc en fonction de l'espacement entre les nœuds cousins, les cousins au second degré, etc. ils peuvent être écrasés ensemble et se chevauchent. L'utilisation de .nodeSize() indique simplement que chaque nœud devrait obtenir autant d'espace, donc, ils ne se chevauchent!

Le code qui a fini par fonctionner pour moi était

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

Sans horizontalSeparationBetweenNodes et verticalSeparationBetweenNodes les bords des nœuds se touchaient. J'ai également ajouté ceci .separation() pour diminuer la quantité d'espace entre les nœuds cousins, car mes nœuds sont assez larges et beaucoup d'espace était gaspillé.

Note: Ce EST POUR d3 v3, pas v4

11
répondu Danny Harding 2017-02-03 21:21:02

Tout d'abord, merci à tous ceux qui ont posté avant, l'or pur. Je voulais ajouter à ce post pour ceux qui pourraient être aux prises avec le problème de décalage associé à un arbre dessiné horizontalement.

La clé est, si vous passez de .taille() pour .nodeSize() sur un arbre horizontal, vous remarquerez que votre nœud racine semble sauter/réorienter pour être situé à (0,0). Et par la d3.documentation js c'est en fait le cas (voir https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize )

Cependant, pour l'ajuster il vous suffit de vous assurer de réorienter votre viewBox. C'est-à-dire, lorsque vous .append votre svg, vous devez définir explicitement votre viewBox. Voici ma petite ligne hacky où cela a fonctionné pour moi...

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 + ")");
0
répondu Kevin Gunn 2017-11-15 15:05:38