web-dev-qa-db-fra.com

Séparation de la structure de l'arborescence D3 entre les nœuds à l'aide de NodeSize

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

enter image description here

J'ai jeté un coup d'oeil et 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é ceci article de blog parlant de la question mais il dit

La propriété size n’existe pas dans les nœuds, ce sera donc la propriété sur laquelle vous souhaitez contrôler la taille.

mais, de toute évidence, il existe une méthode nodeSize, donc j’ai l’impression que j’utilise simplement la méthode de manière incorrecte et/ou que la publication de blog n’est pas à jour. Je souhaite que mes nœuds aient la taille du rectangle et les espacent de manière égale afin qu'ils ne se chevauchent pas. Est-ce que quelqu'un sait 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 ne pouvais pas non plus trouver beaucoup d'exemples où les gens changeaient la taille des nœuds ou avaient besoin d'une séparation pour les objets rectangulaires (il y avait quelques exemples concernant des objets circulaires mais j'estime 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 + ")");
32
aug

UPDATE 05/04/2018: Je crois comprendre que le d3 a beaucoup changé (pour le meilleur) pour être beaucoup plus modulaire. Pour ceux qui recherchent cette réponse, il utilisait une version beaucoup plus ancienne de d3 (plus précisément la v3). 

Un grand nombre des résultats sont toujours pertinents pour le package d3-hierarchy sous cluster.size() ET cluster.nodeSize() et j'ai l'intention de mettre à jour potentiellement mon exemple pour l'utiliser. Pour référence historique cependant, je laisse le fond intact.


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

EDIT: Mise à 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 créer facilement. J'essaierai également d'ajouter l'exemple directement à cette réponse une fois que j'aurai réduit la quantité de contenu qu'elle contient.

_ { http://codepen.io/augbog/pen/LEXZKK } _

Mise à jour de cette réponse. J'ai parlé avec mon ami et nous avons examiné 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 une size pour l’arborescence, vous définissez une taille fixe afin que l’arborescence soit conforme à cette largeur et à cette hauteur. Lorsque vous définissez une nodeSize, l'arborescence doit être dynamique pour pouvoir réinitialiser la taille de l'arborescence. 

Quand j’ai spécifié size après nodeSize, j’étais en train de passer outre à ce que je voulais haha ​​...

Ligne inférieure: 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 une size si vous déclarez une nodeSize.

EDIT: D3.js en fait mise à jour de la documentation _. Merci à ceux qui ont fait ça parce que c'est beaucoup plus clair maintenant!

La propriété nodeSize est exclusive avec tree.size; réglage tree.nodeSize définit tree.size sur null.

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

Picture where nodeSize is set at width of 100 and height of 30

43
aug

Je n'avais pas bien compris la réponse acceptée avant d'avoir fait mes propres recherches, alors j'ai pensé partager ce que j'ai trouvé ...

Si vous utilisez .size() et que vos nœuds se chevauchent, utilisez plutôt .nodeSize()

Comme expliqué dans la réponse acceptée, .size() définit la taille disponible de l'arbre et dépend donc de l'espacement entre les noeuds cousins, les cousins ​​secondaires, etc. Utiliser .nodeSize() signifie simplement que chaque nœud doit avoir autant d’espace, afin qu’ils ne se chevauchent jamais!

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 touchent. J'ai également ajouté cette .separation() pour réduire la quantité d'espace entre les nœuds cousins, car mes nœuds sont très larges et que beaucoup d'espace était gaspillé.

Note: Ceci est pour d3 v3, pas v4

11
Danny Harding

Tout d’abord, merci à tous ceux qui ont déjà posté, or pur… Je voulais ajouter quelque chose à ce billet pour ceux qui pourraient avoir des problèmes avec le problème de décalage associé à un arbre dessiné horizontalement.

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

Cependant, pour ajuster, vous devez simplement vous assurer de réorienter votre viewBox. C'est-à-dire que 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
Kevin Gunn