2017-04-23 69 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