2012-07-21 140 views
29

我正在使用d3.js樹,並且想要動態添加節點,而不是預加載整個樹。d3.js如何將節點動態添加到樹中

如何修改以下內容以便在單擊節點時動態添加其他JSON節點? (見下面的鏈接,和下面的代碼)

http://mbostock.github.com/d3/talk/20111018/tree.html

因此而不是預先加載整個樹,而不是我想取回被點擊父只有當孩子節點。我可以檢索切換函數中的子節點的json,但我無法弄清楚如何將它們添加到樹中。

var m = [20, 120, 20, 120], 
    w = 1280 - m[1] - m[3], 
    h = 800 - m[0] - m[2], 
    i = 0, 
    root; 

var tree = d3.layout.tree() 
    .size([h, w]); 

var diagonal = d3.svg.diagonal() 
    .projection(function(d) { return [d.y, d.x]; }); 

var vis = d3.select("#body").append("svg:svg") 
    .attr("width", w + m[1] + m[3]) 
    .attr("height", h + m[0] + m[2]) 
    .append("svg:g") 
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); 

d3.json("flare.json", function(json) { 
    root = json; 
    root.x0 = h/2; 
    root.y0 = 0; 

    function toggleAll(d) { 
    if (d.children) { 
     d.children.forEach(toggleAll); 
     toggle(d); 
    } 
    } 

    // Initialize the display to show a few nodes. 
    root.children.forEach(toggleAll); 
    toggle(root.children[1]); 
    toggle(root.children[1].children[2]); 
    toggle(root.children[9]); 
    toggle(root.children[9].children[0]); 

    update(root); 
}); 

function update(source) { 
    var duration = d3.event && d3.event.altKey ? 5000 : 500; 

    // Compute the new tree layout. 
    var nodes = tree.nodes(root).reverse(); 

    // Normalize for fixed-depth. 
    nodes.forEach(function(d) { d.y = d.depth * 180; }); 

    // Update the nodes… 
    var node = vis.selectAll("g.node") 
     .data(nodes, function(d) { return d.id || (d.id = ++i); }); 

    // Enter any new nodes at the parent's previous position. 
    var nodeEnter = node.enter().append("svg:g") 
     .attr("class", "node") 
     .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) 
     .on("click", function(d) { toggle(d); update(d); }); 

    nodeEnter.append("svg:circle") 
     .attr("r", 1e-6) 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 

    nodeEnter.append("svg:text") 
     .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) 
     .attr("dy", ".35em") 
     .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) 
     .text(function(d) { return d.name; }) 
     .style("fill-opacity", 1e-6); 

    // Transition nodes to their new position. 
    var nodeUpdate = node.transition() 
     .duration(duration) 
     .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); 

    nodeUpdate.select("circle") 
     .attr("r", 4.5) 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 

    nodeUpdate.select("text") 
     .style("fill-opacity", 1); 

    // Transition exiting nodes to the parent's new position. 
    var nodeExit = node.exit().transition() 
     .duration(duration) 
     .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) 
     .remove(); 

    nodeExit.select("circle") 
     .attr("r", 1e-6); 

    nodeExit.select("text") 
     .style("fill-opacity", 1e-6); 

    // Update the links… 
    var link = vis.selectAll("path.link") 
     .data(tree.links(nodes), function(d) { return d.target.id; }); 

    // Enter any new links at the parent's previous position. 
    link.enter().insert("svg:path", "g") 
     .attr("class", "link") 
     .attr("d", function(d) { 
     var o = {x: source.x0, y: source.y0}; 
     return diagonal({source: o, target: o}); 
     }) 
    .transition() 
     .duration(duration) 
     .attr("d", diagonal); 

    // Transition links to their new position. 
    link.transition() 
     .duration(duration) 
     .attr("d", diagonal); 

    // Transition exiting nodes to the parent's new position. 
    link.exit().transition() 
     .duration(duration) 
     .attr("d", function(d) { 
     var o = {x: source.x, y: source.y}; 
     return diagonal({source: o, target: o}); 
     }) 
     .remove(); 

    // Stash the old positions for transition. 
    nodes.forEach(function(d) { 
    d.x0 = d.x; 
    d.y0 = d.y; 
    }); 
} 

// Toggle children. 
function toggle(d) { 

    // I could retrieve the child nodes here, but how to add them to the tree? 

    if (d.children) { 
    d._children = d.children; 
    d.children = null; 
    } else { 
    d.children = d._children; 
    d._children = null; 
    } 
} 

回答

24

我能夠動態地在切換功能加入以下代碼添加節點:

$.getJSON(addthese.json, function(addTheseJSON) { 
    var newnodes = tree.nodes(addTheseJSON.children).reverse(); 
    d.children = newnodes[0]; 
    update(d); 
}); 

注:我使用jQuery來檢索JSON文件

+0

該更新函數來自哪裏? – Fatih 2013-03-02 09:34:59

+0

你是什麼意思?這是在我的問題上面的代碼。 – 2013-03-04 10:52:25

+1

啊,對。我無法意識到你是同一個人。我的錯! – Fatih 2013-03-05 07:27:09

0

我是新到D3,但這個原始代碼可能會有所幫助。您可以創建一個JSON對象並將其推送到樹/鏈接中。那麼這只是重繪樹的問題。

function createTreeNode(source){ 

var current_node = tree.nodes(source); 
var myJSONObject = {"name": "new Node","children": []}; 

if(current_node[0]._children!=null){ 
current_node[0]._children.push(myJSONObject); 
console.log(current_node[0]._children); 
source.children = source._children; 
source._children = null; 
} 

else if(current_node[0].children!=null && current_node[0]._children!=null){ 
current_node[0].children.push(myJSONObject); 
console.log(current_node[0].children); 
} 

else{ 
current_node[0].children=[] 
current_node[0].children.push(myJSONObject); 
console.log(current_node[0].children); 
} 

tree.links(current_node).push(current_node[current_node.length-1]); 
navigate_tree(source);}