2014-11-12 23 views
5

Tôi tạo ra này mạng nhấp mở rộng-sụp đổ - http://jsfiddle.net/5Lv8gkqv/kích thước Node tỉ lệ với số trẻ em trong 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);}); 
    } 
} 

Điều bây giờ là tôi đã tự hỏi nếu nó có thể có nút kích thước tỷ lệ với số của trẻ em. Vì vậy, nút cha sẽ là vòng tròn lớn nhất và nút lá sẽ là nhỏ nhất, trong khi kích thước nút trung gian sẽ phụ thuộc vào số lượng trẻ em có.

+1

Nếu bạn chỉ tìm kiếm trẻ em ngay lập tức, bạn chỉ cần nhận được 'd.children.length' khi đặt bán kính: http://jsfiddle.net/5Lv8gkqv/1/ –

Trả lời

2

Cập nhật: Bây giờ tính đến trẻ em không được hiển thị, sử dụng ý tưởng từ câu trả lời của @ Gilsha.


Chắc chắn, bạn có thể đặt mỗi <circle> 's bán kính tỉ lệ với số trẻ em mà họ có:

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

nơi r là một số bán kính. Sử dụng r=10 và chuyển đổi qua lại vào nút "wafer", bạn có được điều này: enter image description here

+0

thats làm việc tốt nhưng tôi phải bấm trên "wafer" để làm cho kích thước của nó tăng tỷ lệ thuận với số lượng trẻ em. Theo mặc định Chocolate xuất hiện lớn nhất, trong khi 4 đứa trẻ của nó có cùng kích cỡ. Trong đó shudnt xảy ra coz "Milk" có hai con và do đó "sữa" shud được sắp xếp lên lớn thứ hai nút kích thước. Hy vọng bạn có ý tưởng – shalini

+0

@shalini: Tốt, hãy xem câu trả lời cập nhật của tôi. – mdml

7

Bạn có thể sử dụng d3.scale.linear để tính bán kính của các nút tương ứng với số lượng trẻ em. d3.scale cũng giúp tìm bán kính ở giữa phạm vi. Dưới đây là các cập nhật fiddle

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

tác phẩm của bạn hoàn hảo – shalini

2

Đối với một giải pháp hoàn chỉnh, bạn sẽ thực sự muốn sử dụng một hàm đệ quy để tính toán đầu tiên tổng trẻ em (không chỉ lần đầu tiên cấp trẻ em) của mỗi nút. Ví dụ:

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

Từ đó bạn có thể sử dụng d3.scale như đã ghi nhận ở @ câu trả lời Gilsha để tính toán kích thước dựa trên total_children thuộc tính mới trên mỗi nút.

+1

Thông tin chi tiết hữu ích là – shalini

+1

Thuật toán đệ quy [giải quyết mọi thứ] (https://www.youtube.com/watch?v=0zRjU038vl0)! –

Các vấn đề liên quan