2017-04-23 6 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座標はありません。 addNodeAndEdgesの既存のオブジェクトとの一貫性のある参照を使用して、

Here's a fiddle that fixes thatを使用して、

+0

このように見えます。ありがとう!あなたのフィドルで最初のリンク 'links.push({source:{id:NODE_CNT}、ターゲット:{id:NODE_CNT - 1}})'はその矢のためにレンダリングされますが、間違ったインデックスの問題だと思います。私は実際には非常にnoobの間違いだった(私はそれがd3ドメインの問題だと思った..) – alfredopacino

関連する問題