Briser le texte de json en plusieurs lignes pour afficher les étiquettes dans une disposition de force D3

Je suis nouveau dans d3.js et codé en général. C'est ma question:

J'essaie de trouver un moyen de briser les noms des objets de mise en page des lignes longues.

Je voudrais pouvoir déterminer où rompre ces lignes, et je suppose que c'est quelque chose qui pourrait être possible à partir du fichier json.

Je suis conscient qu'il y a déjà eu des questions similaires, mais je ne peux pas trouver où mettre le code ou pourquoi mes tentatives précédentes n'ont pas été couronnées de succès. C'est le code que j'ai:

var width = 960, height = 800, root; var force = d3.layout.force() .linkDistance(120) .charge(-600) .gravity(.06) .size([width, height]) .on("tick", tick); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var link = svg.selectAll(".link"), node = svg.selectAll(".node"); d3.json("graph.json", function(error, json) { root = json; update(); }); function update() { var nodes = flatten(root), links = d3.layout.tree().links(nodes); // Restart the force layout. force .nodes(nodes) .links(links) .start(); // Update links. link = link.data(links, function(d) { return d.target.id; }); link.exit().remove(); link.enter().insert("line", ".node") .attr("class", "link"); // Update nodes. node = node.data(nodes, function(d) { return d.id; }); node.exit().remove(); var nodeEnter = node.enter().append("g") .attr("class", "node") .on("click", click) .call(force.drag); nodeEnter.append("circle") .attr("r", function(d) { return Math.sqrt(d.size) / 3 || 10; }); nodeEnter.append("text") .attr("dy", "0.3em") .text(function(d) { return d.name; }); node.select("circle") .style("fill", color); } // Divide text text.append("text") .each(function (d) { var arr = d.name.split(" "); if (arr != undefined) { for (i = 0; i < arr.length; i++) { d3.select(this).append("tspan") .text(arr[i]) .attr("dy", i ? "1.2em" : 0) .attr("x", 0) .attr("text-anchor", "middle") .attr("class", "tspan" + i); } } }); // Divide text function tick() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("transform", function(d) { return "translate(" + dx + "," + dy + ")"; }); } function color(d) { return d._children ? "#9ecae1" // collapsed package : d.children ? "#ffffff" // expanded package : "#ffcc50"; // leaf node } // Toggle children on click. function click(d) { if (d3.event.defaultPrevented) return; // ignore drag if (d.children) { d._children = d.children; d.children = null; } else if (d._children) { d.children = d._children; d._children = null; } else { // This was a leaf node, so redirect. window.open(d.url, 'popUpWindow','height=600,width=800,left=10,top=10,resizable=yes,scrollbars=no,toolbar=no,menubar=no,location=no,directories=no,status=yes'); } update(); } // Returns a list of all nodes under the root. function flatten(root) { var nodes = [], i = 0; function recurse(node) { if (node.children) node.children.forEach(recurse); if (!node.id) node.id = ++i; nodes.push(node); } recurse(root); return nodes; } 

Et ce sont les informations de json:

 { "name": "flare", "children": [ { "name": "analytics", "children": [ { "name": "cluster", "children": [ {"name": "Agglomerative Cluster", "size": 3938}, {"name": "Community Structure", "size": 3812}, {"name": "Hierarchical Cluster", "size": 6714}, {"name": "Merge Edge", "size": 743} ] }, { "name": "graph", "children": [ {"name": "Betweenness Centrality", "size": 3534}, {"name": "Link Distance", "size": 5731}, {"name": "Max Flow Min Cut", "size": 7840}, {"name": "Shortest Paths", "size": 5914}, {"name": "Spanning Tree", "size": 3416} ] }, { "name": "optimization", "children": [ {"name": "Aspect Ratio Banker", "size": 7074} ] } ] } ] 

Je voudrais pouvoir, par exemple, décider de casser Aspect / Ratio Banker ou Aspect Ratio / Banker.

Je crois que cet exemple sur jsfiddle résout votre problème.

Le code est en fait votre exemple, juste un peu modifié.

Il existe une nouvelle fonction wordwrap2 () qui prend soin de répartir correctement les noms:

 function wordwrap2( str, width, brk, cut ) { brk = brk || '\n'; width = width || 75; cut = cut || false; if (!str) { return str; } var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)'); return str.match( RegExp(regex, 'g') ).join( brk ); } 

Ensuite, il existe une nouvelle partie importante du code qui, au lieu de créer simplement une étiquette de texte par nœud, crée ceci:

  var maxLength = 20; var separation = 18; var textX = 0; nodeEnter.append("text") .attr("dy", "0.3em") .each(function (d) { var lines = wordwrap2(d.name, maxLength).split('\n'); console.log(d.name); console.log(lines); for (var i = 0; i < lines.length; i++) { d3.select(this) .append("tspan") .attr("dy", separation) .attr("x", textX) .text(lines[i]); } }); 

(Variable maxLength – longueur utilisée pour le critère pour diviser les noms)

(Séparation variable – distance verticale visuelle entre les lignes divisées d'un nom)

Par exemple, ce serait la sortie pour maxLength = 20:

MaxLength = 20

Ce serait le résultat pour maxLength = 15: notez que Aspect Ratio Banker est devenu Aspect Ratio / Banker)

MaxLength = 15

Ce serait la sortie pour maxLength = 10: (maintenant, regardez Aspect / Ratio / Banker!)

MaxLength = 10

Et ce serait la sortie pour maxLength = 10 et la séparation = 30 (un peu plus d'espace entre les lignes individuelles):

MaxLength = 10 separation = 30