2017-04-23 76 views
0

我想用點擊節點上的新節點和邊緣來有針對性地更新有向圖。 我已經從這個例子開始https://bl.ocks.org/mbostock/1095795 但目前我不知道如何處理奇怪定位的新邊(和箭頭)。 https://jsfiddle.net/alfredopacino/z1ppabL0/點擊更新圖表

var svg = d3.select("svg"), 
     width = +svg.attr("width"), 
     height = +svg.attr("height"), 
     color = d3.scaleOrdinal(d3.schemeCategory10); 

    var a = {id: "1"}, 
     b = {id: "2"}, 
     c = {id: "3"}, 
     nodes = [a, b, c], 
     links = [], 
     NODE_CNT = nodes.length; //the nodes count so long 

    links.push({source: a, target: b}); // Add a-b. 
    links.push({source: b, target: c}); // Add b-c. 
    links.push({source: c, target: a}); // Add c-a. 

    var simulation = d3.forceSimulation(nodes) 
     .force("charge", d3.forceManyBody().strength(-1000)) 
     .force("link", d3.forceLink(links).distance(200)) 
     .force("x", d3.forceX()) 
     .force("y", d3.forceY()) 
     .alphaTarget(1) 
     .on("tick", ticked); 

    var g = svg.append("g").attr("transform", "translate(" + width/2 + "," + height/2 + ")"), 
     link = g.append("g").attr("stroke", "#000").attr("stroke-width", 1.5).selectAll(".link"); 
    // build the arrow. 
    svg.append("svg:defs").selectAll("marker") 
     .data(["end"])  // Different link/path types can be defined here 
     .enter().append("svg:marker") // This section adds in the arrows 
     .attr("id", String) 
     .attr("viewBox", "0 -5 10 10") 
     .attr("refX", 15) 
     .attr("refY", -1.5) 
     .attr("markerWidth", 6) 
     .attr("markerHeight", 6) 
     .attr("orient", "auto") 
     .append("svg:path") 
     .attr("d", "M0,-5L10,0L0,5"); 

    var node = g.append("g").attr("stroke", "#fff").attr("stroke-width", 1.5).selectAll(".node"); 

    update(); 

    function update() { 

     // Apply the general update pattern to the nodes. 
     node = node.data(nodes, function (d) { 
      return d.id; 
     }); 
     node.exit().remove(); 
     node = node.enter().append("circle").attr("fill", function (d) { 
      return color(d.id); 
     }).attr("r", 8).merge(node); 
     node.on("click", addNodeAndEdges); 

     // Apply the general update pattern to the links. 
     link = link.data(links, function (d) { 
      return d.source.id + "-" + d.target.id; 
     }); 
     link.exit().remove(); 
     link = link.enter().append("line").merge(link) 
      .attr("marker-end", "url(#end)"); //-----------------arrow---------- 

     // Update and restart the simulation. 
     simulation.nodes(nodes); 
     simulation.force("link").links(links); 
     simulation.alpha(1).restart(); 
    } 

    function ticked() { 
     node.attr("cx", function (d) { 
      return d.x; 
     }) 
      .attr("cy", function (d) { 
       return d.y; 
      }) 

     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; 
      }); 
    } 
    function addNodeAndEdges(d) { 
     //select(d) references the data, not the element. You need to select(this) 
     console.log(this) 
     NODE_CNT++; 
     nodes.push({id: NODE_CNT}); 
     links.push({source: {id: NODE_CNT}, target: {id: NODE_CNT - 1}}); 
     links.push({source: {id: NODE_CNT - 2}, target: {id: NODE_CNT}}); 

     d3.select(this).attr('r', 20) 
      .style("fill", "lightcoral") 
      .style("stroke", "red"); 
     update(); 
    } 

回答

1

的問題是在你的addNodeAndEdges功能。當您向nodeslinks添加新元素時,您正在創建新對象,而不是引用現有對象。例如,當您推送源爲{id: 1}的鏈接時,這與具有a源的鏈接不同。當力仿真設置xy屬性a時,新鏈接的源節點也不會更新。所以你添加的新路徑沒有x和y座標。

Here's a fiddle that fixes that,通過對addNodeAndEdges中的現有對象使用一致的引用。

+0

看起來像這樣解決了,謝謝!在你的第一個鏈接links.push({source:{id:NODE_CNT},target:{id:NODE_CNT - 1}});'是爲了它的箭頭而渲染的,但我猜這是索引錯誤的問題。我的確是一個非常小的錯誤(我認爲這是一個D3域問題..) – alfredopacino