简体   繁体   中英

D3 Leaf Nodes - many elements overlaps

i'm using D3JS in the following JSFiddle Example: HERE

I'm experiencing a strange issue: when i have a lot of leaf nodes on my graph, the leafs overlaps between them, currently, i've tried to use many strategies to go (like the .separation(function(a, b) { return (a.parent == b.parent ? 1 : 5 ) }) ) on the nodes but with no luck.

Take note that i can have a D3 Charts with 500/600 leaf nodes and them must be readable.

My goal is to increase the space between the leaf nodes and make them readable and not overlapped, how i can do that?

The tree and cluster layouts will do a separation based on the available space. Therefore, that value you passed is not an absolute value (in pixels, for instance), but just a proportion.

You have to tell D3 how much SVG height (or width) you need. For instance, you can calculate the number of leaves in the root ...

var numberOfLeaves = countLeaves(root);

function countLeaves(obj) {
  var leaves = 0;
  recursiveCounter(obj);
  function recursiveCounter(obj) {
    if (obj.children) {
      for (var i = 0; i < obj.children.length; i++) {
        if (obj.children[i].children) {
          recursiveCounter(obj.children[i]);
        } else {
          leaves++;
        };
      };
    };
  }
  return leaves;
};

And change the width accordingly:

var nodeHeight = 12;

height = nodeHeight * numberOfLeaves;

Here is the code with that change:

 var width = 1000, height = 1000; var diameter = 300; var duration = 2000; d3.selectAll("input").on("change", change); function change() { if (this.value === "radialtree") transitionToRadialTree(); else if (this.value === "radialcluster") transitionToRadialCluster(); else if (this.value === "tree") transitionToTree(); else transitionToCluster(); }; function transitionToRadialTree() { var nodes = radialTree.nodes(root), // recalculate layout links = radialTree.links(nodes); svg.transition().duration(duration) .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")"); // set appropriate translation (origin in middle of svg) link.data(links) .transition() .duration(duration) .style("stroke", "#fc8d62") .attr("d", radialDiagonal); //get the new radial path node.data(nodes) .transition() .duration(duration) .attr("transform", function(d) { return "rotate(" + (dx - 90) + ")translate(" + dy + ")"; }); node.select("circle") .transition() .duration(duration) .style("stroke", "#984ea3"); }; function transitionToRadialCluster() { var nodes = radialCluster.nodes(root), // recalculate layout links = radialCluster.links(nodes); svg.transition().duration(duration) .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")"); // set appropriate translation (origin in middle of svg) link.data(links) .transition() .duration(duration) .style("stroke", "#66c2a5") .attr("d", radialDiagonal); //get the new radial path node.data(nodes) .transition() .duration(duration) .attr("transform", function(d) { return "rotate(" + (dx - 90) + ")translate(" + dy + ")"; }); node.select("circle") .transition() .duration(duration) .style("stroke", "#4daf4a"); }; function transitionToTree() { var nodes = tree.nodes(root), //recalculate layout links = tree.links(nodes); svg.transition().duration(duration) .attr("transform", "translate(40,0)"); link.data(links) .transition() .duration(duration) .style("stroke", "#e78ac3") .attr("d", diagonal); // get the new tree path node.data(nodes) .transition() .duration(duration) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }); node.select("circle") .transition() .duration(duration) .style("stroke", "#377eb8"); }; function transitionToCluster() { var nodes = cluster.nodes(root), //recalculate layout links = cluster.links(nodes); svg.transition().duration(duration) .attr("transform", "translate(40,0)"); link.data(links) .transition() .duration(duration) .style("stroke", "#8da0cb") .attr("d", diagonal); //get the new cluster path node.data(nodes) .transition() .duration(duration) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }); node.select("circle") .transition() .duration(duration) .style("stroke", "#e41a1c"); }; var root = getData(); var nodeHeight = 12; var numberOfLeaves = countLeaves(root); function countLeaves(obj) { var leaves = 0; recursiveCounter(obj); function recursiveCounter(obj) { if (obj.children) { for (var i = 0; i < obj.children.length; i++) { if (obj.children[i].children) { recursiveCounter(obj.children[i]); } else { leaves++; }; }; }; } return leaves; }; height = nodeHeight * numberOfLeaves; var tree = d3.layout.tree() .separation(function(a, b) { return (a.parent == b.parent ? 1 : 5) }) .size([height, width - 160]); var cluster = d3.layout.cluster() .separation(function(a, b) { return (a.parent == b.parent ? 1 : 5) }) .size([height, width - 160]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [dy, dx]; }); var radialTree = d3.layout.tree() .size([360, diameter / 2]) .separation(function(a, b) { return (a.parent == b.parent ? 1 : 5) / a.depth; }); var radialCluster = d3.layout.cluster() .size([360, diameter / 2]) .separation(function(a, b) { return (a.parent == b.parent ? 1 : 5) / a.depth; }); var radialDiagonal = d3.svg.diagonal.radial() .projection(function(d) { return [dy, dx / 180 * Math.PI]; }); function responsivefy(svg) { // get container + svg aspect ratio var container = d3.select(svg.node().parentNode), width = parseInt(svg.style("width")), height = parseInt(svg.style("height")), aspect = width / height; // add viewBox and preserveAspectRatio properties, // and call resize so that svg resizes on inital page load svg.attr("viewBox", "0 0 " + width + " " + height) .attr("preserveAspectRatio", "xMinYMid") .call(resize); // to register multiple listeners for same event type, // you need to add namespace, ie, 'click.foo' // necessary if you call invoke this function for multiple svgs // api docs: https://github.com/mbostock/d3/wiki/Selections#on d3.select(window).on("resize." + container.attr("id"), resize); // get width of container and resize svg to fit it function resize() { var targetWidth = parseInt(container.style("width")); svg.attr("width", targetWidth); svg.attr("height", Math.round(targetWidth / aspect)); } } var nodes = cluster.nodes(root), links = cluster.links(nodes); var svg = d3.select("#test").append("svg") .attr("width", width) .attr("height", height) .call(responsivefy) .append("g") .attr("transform", "translate(40,0)"); var link = svg.selectAll(".link") .data(links) .enter() .append("path") .attr("class", "link") .style("stroke", "#8da0cb") .attr("d", diagonal); var node = svg.selectAll(".node") .data(nodes) .enter() .append("g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }); node.append("circle") .attr("r", 4.5) .style("stroke", "#e41a1c"); node.append("text") .attr("dx", function(d) { return d.children ? -8 : 8; }) .attr("dy", 3) .style("text-anchor", function(d) { return d.children ? "end" : "start"; }) .text(function(d) { return d.name; }); function getData() { return { "name": "This Instance", "children": [{ "name": "TEST", "children": [{ "name": "FM Sala 1 [L1] AC Sala 1 [L2] FM Open Space [L3]", "children": [{ "name": "VLN1" }, { "name": "VLN2" }, { "name": "VLN3" }, { "name": "VLN_AVG" }, { "name": "VL1-2" }, { "name": "VL2-3" }, { "name": "VL3-1" }, { "name": "VLL_AVG" }, { "name": "IL1" }, { "name": "IL2" }, { "name": "IL3" }, { "name": "IL_AVG" }, { "name": "PL1" }, { "name": "PL2" }, { "name": "PL3" }, { "name": "PL_SUM" }, { "name": "QL1" }, { "name": "QL2" }, { "name": "QL3" }, { "name": "QL_SUM" }, { "name": "SL1" }, { "name": "SL2" }, { "name": "SL3" }, { "name": "SL_SUM" }, { "name": "Cos_L1" }, { "name": "Cos_L2" }, { "name": "Cos_L3" }, { "name": "Cos_LSUM" }, { "name": "kWh_L1" }, { "name": "kWh_L2" }, { "name": "kWh_L3" }, { "name": "KVARh_L1" }, { "name": "KVARh_L2" }, { "name": "KVARh_L3" }, { "name": "KVARh_LSUM" }, { "name": "KVAh_L1" }, { "name": "KVAh_L2" }, { "name": "KVAh_L3" }, { "name": "KVAh_LSUM" }] }, { "name": "Luci Open Space [L-1-2-3]", "children": [{ "name": "VLN1" }, { "name": "VLN2" }, { "name": "VLN3" }, { "name": "VLN_AVG" }, { "name": "VL1-2" }, { "name": "VL2-3" }, { "name": "VL3-1" }, { "name": "VLL_AVG" }, { "name": "IL1" }, { "name": "IL2" }, { "name": "IL3" }, { "name": "IL_AVG" }, { "name": "PL1" }, { "name": "PL2" }, { "name": "PL3" }, { "name": "QL3" }, { "name": "QL1" }, { "name": "QL2" }, { "name": "QL_SUM" }, { "name": "SL1" }, { "name": "SL2" }, { "name": "SL3" }, { "name": "SL_SUM" }, { "name": "Cos_L1" }, { "name": "Cos_L2" }, { "name": "Cos_L3" }, { "name": "Cos_LSUM" }, { "name": "PL_SUM" }, { "name": "kWh_L1" }, { "name": "kWh_L2" }, { "name": "kWh_L3" }, { "name": "KVAh_L1" }, { "name": "KVAh_L2" }, { "name": "KVAh_L3" }, { "name": "KVAh_LSUM" }, { "name": "KVARh_LSUM" }, { "name": "KVARh_L3" }, { "name": "KVARh_L2" }, { "name": "KVARh_L1" }] }, { "name": "Centrale Termica [L1-2-3]", "children": [{ "name": "VLN1" }, { "name": "VLN2" }, { "name": "VLN3" }, { "name": "VLN_AVG" }, { "name": "VL1-2" }, { "name": "VL2-3" }, { "name": "VL3-1" }, { "name": "VLL_AVG" }, { "name": "IL1" }, { "name": "IL2" }, { "name": "IL3" }, { "name": "IL_AVG" }, { "name": "PL1" }, { "name": "PL2" }, { "name": "PL3" }, { "name": "QL3" }, { "name": "QL1" }, { "name": "QL2" }, { "name": "QL_SUM" }, { "name": "SL1" }, { "name": "SL2" }, { "name": "SL3" }, { "name": "SL_SUM" }, { "name": "Cos_L1" }, { "name": "Cos_L2" }, { "name": "Cos_L3" }, { "name": "Cos_LSUM" }, { "name": "PL_SUM" }, { "name": "kWh_L1" }, { "name": "kWh_L2" }, { "name": "kWh_L3" }, { "name": "KVAh_L1" }, { "name": "KVAh_L2" }, { "name": "KVAh_L3" }, { "name": "KVAh_LSUM" }, { "name": "KVARh_LSUM" }, { "name": "KVARh_L3" }, { "name": "KVARh_L2" }, { "name": "KVARh_L1" }] }, { "name": "UPS Rack Main [L3]", "children": [{ "name": "VLN1" }, { "name": "VLN2" }, { "name": "VLN3" }, { "name": "VLN_AVG" }, { "name": "VL1-2" }, { "name": "VL2-3" }, { "name": "VL3-1" }, { "name": "VLL_AVG" }, { "name": "IL1" }, { "name": "IL2" }, { "name": "IL3" }, { "name": "IL_AVG" }, { "name": "PL1" }, { "name": "PL2" }, { "name": "PL3" }, { "name": "QL3" }, { "name": "QL1" }, { "name": "QL2" }, { "name": "QL_SUM" }, { "name": "SL1" }, { "name": "SL2" }, { "name": "SL3" }, { "name": "SL_SUM" }, { "name": "Cos_L1" }, { "name": "Cos_L2" }, { "name": "Cos_L3" }, { "name": "Cos_LSUM" }, { "name": "PL_SUM" }, { "name": "kWh_L1" }, { "name": "kWh_L2" }, { "name": "kWh_L3" }, { "name": "KVAh_L1" }, { "name": "KVAh_L2" }, { "name": "KVAh_L3" }, { "name": "KVAh_LSUM" }, { "name": "KVARh_LSUM" }, { "name": "KVARh_L3" }, { "name": "KVARh_L2" }, { "name": "KVARh_L1" }] }, { "name": "Generale [L-1-2-3]", "children": [{ "name": "VLN1" }, { "name": "VLN2" }, { "name": "VLN3" }, { "name": "VLN_AVG" }, { "name": "VL1-2" }, { "name": "VL2-3" }, { "name": "VL3-1" }, { "name": "VLL_AVG" }, { "name": "IL1" }, { "name": "IL2" }, { "name": "IL3" }, { "name": "IL_AVG" }, { "name": "PL1" }, { "name": "PL2" }, { "name": "PL3" }, { "name": "QL3" }, { "name": "QL1" }, { "name": "QL2" }, { "name": "QL_SUM" }, { "name": "SL1" }, { "name": "SL2" }, { "name": "SL3" }, { "name": "SL_SUM" }, { "name": "Cos_L1" }, { "name": "Cos_L2" }, { "name": "Cos_L3" }, { "name": "Cos_LSUM" }, { "name": "PL_SUM" }, { "name": "kWh_L1" }, { "name": "kWh_L2" }, { "name": "kWh_L3" }, { "name": "KVAh_L1" }, { "name": "KVAh_L2" }, { "name": "KVAh_L3" }, { "name": "KVAh_LSUM" }, { "name": "KVARh_LSUM" }, { "name": "KVARh_L3" }, { "name": "KVARh_L2" }, { "name": "KVARh_L1" }] }, { "name": "open space", "children": [{ "name": "dbm" }] }, { "name": "Luxmetro reception", "children": [{ "name": "lux" }] }, { "name": "Gathered - Gate 1", "children": [{ "name": "people_count" }] }] }, { "name": "test", "children": [{ "name": "Open Space", "children": [{ "name": "carbon_oxide" }] }] }] }; }
 label { font: 12px sans-serif; } .node circle { fill: #fff; stroke: steelblue; stroke-width: 1.5px; } .node { font: 10px sans-serif; } .link { fill: none; stroke: tan; stroke-width: 1.5px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> <form> <label><input type="radio" name="mode" value="radialtree">Radial Tree</label> <label><input type="radio" name="mode" value="radialcluster">Radial Cluster</label> <label><input type="radio" name="mode" value="tree">Tree</label> <label><input type="radio" name="mode" value="cluster" checked>Cluster</label> </form> <div id="test"> </div>

You have to do a similar math for the diameter .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM