2014-11-12 6 views
5

habe ich diese Click-expand-Zusammenbruch Netzwerk - http://jsfiddle.net/5Lv8gkqv/Knoten Größe proportional zur Anzahl der Kinder in D3

var width = 960, 
    height = 500, 
    root = { 
"name": "Chocolate", "tag":"class", 
"children": [ 
    { 
    "name": "Wafer", "tag":"subclass", 
    "children": [ 
    { 
     "name": "Nestle", "tag":"company", 
    "children": [ 
     {"name": "KitKat", "tag":"product"} 
    ] 
    } 
    ] 
    }, 

    { 
    "name": "White", "tag":"subclass", 
    "children": [ 
    { 
     "name": "Nestle", "tag":"company", 
    "children": [ 
     {"name": "Milkybar", "tag":"product"} 
    ] 
    } 
    ] 
    }, 

    { 
    "name": "Caramel", "tag":"subclass", 
    "children": [ 
    { 
     "name": "Nestle", "tag":"company", 
    "children": [ 
     {"name": "BarOne", "tag":"product"} 
    ] 
    } 
    ] 
    },  
    { 
    "name": "Milk", "tag":"subclass", 
    "children": [ 
    { 
     "name": "Nestle", "tag":"company", 
    "children": [ 
     {"name": "Nestle Milk", "tag":"product"} 
    ] 
    }, { 
     "name": "Cadbury", "tag":"company", 
    "children": [ 
     {"name": "Dairy Milk", "tag":"product"} 
    ] 
    } 
    ] 
    } 




] 
}; 

var force = d3.layout.force() 
    .linkDistance(150) 
    .charge(-120) 
    .gravity(.05) 
    .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"); 

flatten(root); //to set ids 
setParents(root, null); 
collapseAll(root); 
root.children = root._children; 
root._children = null; 
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)/10 || 4.5; }); 

    nodeEnter.append("text") 
     .attr("dy", ".35em") 
     .text(function(d) { return d.name; }); 

    node.select("circle") 
     .style("fill", color); 
} 

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(" + d.x + "," + d.y + ")"; }); 
} 

function color(d) { 
    return d._children ? "#3182bd" // collapsed package 
     : d.children ? "#c6dbef" // expanded package 
     : "#fd8d3c"; // leaf node 
} 

// Toggle children on click. 
function click(d) { 
    if (d3.event.defaultPrevented) return; // ignore drag 
    if (d.children) { 
     collapseAll(d); 
    } else { 
     if (d._parent){ 
      d._parent.children.forEach(function(e){ 
       if (e != d){ 
        collapseAll(e); 
       } 
      }); 
     } 
    d.children = d._children; 
    d._children = null; 
    } 
    update(); 
} 

function collapseAll(d){ 
    if (d.children){ 
     d.children.forEach(collapseAll); 
     d._children = d.children; 
     d.children = null; 
    } 
    else if (d._childred){ 
     d._children.forEach(collapseAll); 
    } 
} 

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

function setParents(d, p){ 
    d._parent = p; 
    if (d.children) { 
     d.children.forEach(function(e){ setParents(e,d);}); 
    } else if (d._children) { 
     d._children.forEach(function(e){ setParents(e,d);}); 
    } 
} 

Die Sache ist jetzt, dass ich frage mich, ob seine mögliche Knoten-Größe proportional zur Anzahl haben von Kindern. Also ist der Elternknoten der größte Kreis und der Blattknoten ist der kleinste, während die Zwischenknotengröße von der Anzahl der Kinder abhängt, die sie haben.

+1

Wenn Sie nur nach unmittelbaren Kindern suchen, müssen Sie nur 'd.children.length' beim Einstellen des Radius: http://jsfiddle.net/5Lv8gkqv/1/ –

Antwort

2

Aktualisiert: Jetzt berücksichtigt Kinder, die nicht angezeigt werden, mit der Idee von @ Gilsha's Antwort.


Sicher, können Sie jedes <circle> ‚s Radius eingestellt proportional zu der Anzahl der Kinder, die sie haben:

node.select("circle") 
    .attr("r", function(d){ 
     var numKids = 0; 
     if (d.children) numKids += d.children.length; 
     if (d._children) numKids += d._children.length; 
     return 10 * (numKids + 1); 
}) 

wo r etwas Radius ist. Mit r=10 und Makeln auf dem "wafer" Knoten Sie diese: enter image description here

+0

das funktioniert gut, aber ich muss klicken auf "Wafer", um seine Größe proportional zu seiner Anzahl von Kindern zu machen. Standardmäßig ist Chocolate am größten, während die 4 Kinder gleich groß sind. Welcher Shudnt passiert, coz "Milk" hat zwei Kinder und somit "Milch" shud kommen zweitgrößte Knotengröße. Hoffe, du hast die Idee – shalini

+0

@Shalini: Guter Punkt, siehe meine aktualisierte Antwort. – mdml

7

Sie d3.scale.linear zur Berechnung Radius von Knoten proportional zu der Anzahl der Kinder nutzen können. d3.scale hilft auch, einen Radius zwischen einem Bereich zu finden. Hier wird die fiddle aktualisiert

var minRadius = 10; 
var maxRadius = 15; 
var scale = d3.scale.linear().range([minRadius,maxRadius]); 
nodeEnter.append("circle") 
    .attr("r", function(d) { 
     if(d.children) 
      return scale(d.children.length); 
     else if(d._children) 
      return scale(d._children.length); 
     else 
      return minRadius; 
    }); 
+0

Ihre Werke perfekt – shalini

2

für eine komplette Lösung, Sie wollen tatsächlich eine rekursive Funktion verwenden, um zuerst zu berechnen die Gesamt Kinder (nicht nur First-Level-Kinder) jedes Knotens. Zum Beispiel:

var bubble_up_total_children = function(node) { 
    var child, _i, _len, _ref; 
    if (node.children && node.children.length > 0) { 
    _ref = node.children; 
    for (_i = 0, _len = _ref.length; _i < _len; _i++) { 
     child = _ref[_i]; 
     bubble_up_total_children(child); 
    } 
    node.total_children = node.children.length + node.children.reduce(function(a, b) { 
     return a.total_children + b.total_children; 
    }); 
    } else { 
    node.total_children = 0; 
    } 
}; 

bubble_up_total_children(root); 

Von dort können Sie jetzt d3.scale wie bereits dokumentiert in @ Gilsha Antwort Größe zu berechnen, basierend auf das neue total_children Attribut auf jedem Knoten.

+1

Gute Einsicht, die war – shalini

+1

Rekursive Algorithmen [alles lösen] (https://www.youtube.com/watch?v=0zRjU038vl0)! –