2017-07-15 182 views
0

我试图创建一个网页,用户可以选择节点(使用select2),并且他们选择的每个节点都将被添加到网络中。 我目前无法让节点出现在左上角以外的SVG上。d3.js v4 - 节点卡在左上角

这是我在bl.ocks.org代码: https://bl.ocks.org/shaief/2b4d5cfc7dcc0e03c59f0d6be3cc2913

我一直在寻找,看看有什么其他人一样,但我无法找到,说明我的问题的答案。

编辑: 在我看来,虽然代码运行和滴答,在'勾号'功能它不影响节点对象。我不明白为什么。

EDIT2: 我创建了一个新文件,它是Mike Bostock修改Force Layout II(https://bl.ocks.org/mbostock/0adcc447925ffae87975a3a81628a196)的复制粘贴并添加了我的select2部分。其结果是一个完整的日志:

Uncaught TypeError: Cannot create property 'vx' on string 'node-uuid-1234567890-5' 
    at n (d3.v4.min.js:2) 
    at d3.v4.min.js:2 
    at be.each (d3.v4.min.js:2) 
    at e (d3.v4.min.js:2) 
    at n (d3.v4.min.js:2) 
    at vn (d3.v4.min.js:2) 
    at _n (d3.v4.min.js:2) 

这很奇怪,因为麦克的例子并使用节点ID而不是序号索引和我不明白原因。

EDIT3: 我在这里添加相关的代码,因为我用完全不同的代码更新了我的要点。

<!DOCTYPE html> 
<meta charset="utf-8"> 

<head> 
    <script 
     src="https://code.jquery.com/jquery-3.2.1.min.js" 
     integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" 
     crossorigin="anonymous"></script> 
    <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" /> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script> 
</head> 
<style> 
    .container { 
    margin-top: 10px; 
    display: flex; 
    } 
    .controls { 
    /* padding: 10px; */ 
    width: 350px; 
    } 
    #select-node-names { 
    width: 100%; 
    } 
    .d3-container { 
    flex-grow: 1; 
    } 
    .links line { 
    stroke: #999; 
    stroke-opacity: 0.6; 
    } 
    .nodes circle { 
    stroke: #fff; 
    /* stroke-width: 1.5px; */ 
    stroke-width: 0px; 
    } 
    text { 
    font: 10px sans-serif; 
    color: red; 
    pointer-events: none; 
    text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff; 
    } 
</style> 
<div class='row'> 
    <select id="select-node-names" multiple="multiple"> 
    </select> 
    <div class="container"> 
    <div class="controls"> 
     <div class="test-nodes"></div> 
    </div> 
    <div class="d3-container"> 
     <svg width="960" height="600"></svg> 
    </div> 
    </div> 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
    <script> 
    d3.json("test.json", function(error, graph) { 
     if (error) throw error; 
     $("#select-node-names") 
     .select2(); 
     var svg = d3.select("svg"), 
     width = +svg.attr("width"), 
     height = +svg.attr("height"); 
     // Color scale for node colors 
     var color = d3.scaleOrdinal(d3.schemeCategory10); 
     // Color scale for link colors 
     var linkColor = d3.scaleOrdinal(d3.schemeCategory10); 
     var simulation = d3.forceSimulation(graph.nodes) 
     .force("charge", d3.forceManyBody() 
      .strength(function(d) { 
      return d.degree; 
      })) 
     .force('x', d3.forceX()) 
     .force('y', d3.forceY()) 
     .force("collision", d3.forceCollide(20)) 
     .force("centering", d3.forceCenter(width/2, height/2)) 
     .force("link", d3.forceLink() 
      .id(function(d) { 
      return d.id 
      })) 
     .on("tick", ticked); 
     var nodes = []; 
     var links = []; 
     var nodeNames = Object.values(graph.nodes); 
     var listItem = d3.select("#select-node-names") 
     .selectAll("option") 
     .data(nodeNames) 
     .enter() 
     .append("option") 
     .text(function(d) { 
      return d.object_name; 
     }) 
     .attr("id", function(d) { 
      return d.id; 
     }) 
     .attr("value", function(d) { 
      return d.id; 
     }); 
     linksID = []; 
     graph.links.forEach(function(e) { 
     var sourceNode = graph.nodes[e.source]["id"]; 
     var targetNode = graph.nodes[e.target]["id"]; 
     linksID.push({ 
      source: sourceNode, 
      target: targetNode, 
      value: e.type 
     }); 
     }); 
     $(document.body) 
     .on("change", "#select-node-names", function() { 
      nodes = search($("#select-node-names") 
      .val(), "id", graph.nodes); 
      nodesID = nodes.map(function(d) { 
      return d.id; 
      }); 
      linksSource = search(nodesID, "source", linksID); 
      linksTarget = search(nodesID, "target", linksID); 
      links = []; 
      links = links.concat(linksSource, linksTarget); 
      update(); 
     }); 
     var nodesG = svg.append("g"); 
     var linksG = svg.append("g"); 
     var node = nodesG 
     .selectAll(".nodes") 
     var link = linksG 
     .selectAll(".links") 
     update() 
     function update() { 
     var showSelectedNodes = d3.select(".test-nodes") 
      .html(""); 
     var showSelectedNodes = d3.select(".test-nodes") 
      .selectAll("myText") 
      .data(nodes); 
     showSelectedNodes.exit() 
      .remove(); // EXIT 
     showSelectedNodes.enter() 
      .append("small") // ENTER 
      .text(function(d) { 
      return d.object_name + " // "; 
      }) 
      .merge(showSelectedNodes) // ENTER + UPDATE 
     var node = nodesG 
      .selectAll("circle") 
      .data(nodes); 
     exitNode = node.exit() 
      .remove(); // EXIT 
     node = node.enter() 
      .append("circle") // ENTER 
      .attr("class", "nodes") 
      .attr("r", 10) 
      .attr("fill", function(d) { 
      return color(d.node_type); 
      }) 
      .append("title") 
      .text(function(d) { 
      return "Node: " + d.id + "\nName: " + d.object_name + 
       "\nCoordinates: " + d.x + " - " + d.y; 
      }) 
      .append("text") 
      .attr("dx", 8) 
      .attr("dy", ".31em") 
      .text(function(d) { 
      return d.object_name; 
      }) 
      .call(d3.drag() 
      .on("start", dragstarted) 
      .on("drag", dragged) 
      .on("end", dragended)) 
      .merge(node) // ENTER + UPDATE 
     link = link.enter() 
      .data(links) 
      .append("line") 
      .style('stroke', function(d) { 
      return linkColor(d.type); 
      }) 
      .attr("stroke-width", 2) 
      .append("title") 
      .text(function(d) { 
      return "Source: " + d.source + "\nTarget: " + d.target + 
       "\nType: " + d.type; 
      }); 
     // Update and restart the simulation. 
     simulation.nodes(nodes); 
     simulation.force("link", d3.forceLink() 
      .id(function(d) { 
      return d.id 
      })); 
     simulation.alphaTarget(1); 
     simulation.restart(); 
     } 
     function ticked() { 
     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("cx", function(d) { 
      return d.x; 
      }) 
      .attr("cy", function(d) { 
      return d.y; 
      }) 
      /* node.attr("transform", transform);*/ 
     } 
     function dragstarted(d) { 
     if (!d3.event.active) simulation.alphaTarget(0.3) 
      .restart(); 
     d.fx = null; 
     d.fy = null; 
     } 
     function dragged(d) { 
     d.fx = d3.event.x; 
     d.fy = d3.event.y; 
     } 
     function dragended(d) { 
     if (!d3.event.active) simulation.alphaTarget(0); 
     d.fx = null; 
     d.fy = null; 
     } 
     function transform(d) { 
     return "translate(" + d.x + "," + d.y + ")"; 
     }; 
    }); 
    function search(valuesArray, prop, myArray) { 
     var res = []; 
     for (var i = 0; i < valuesArray.length; i++) { 
     for (var j = 0; j < myArray.length; j++) { 
      if (myArray[j][prop] == valuesArray[i]) { 
      res.push(myArray[j]); 
      break; 
      } 
     } 
     } 
     return res 
    } 
    </script> 

回答

0

眼前的事情,我看到:

  1. 你不添加链接的操作在所有情况下的模拟:应通过simulation.force完成(“..”)的链接(。 link-array

  2. 您需要清楚您使用的链接标识。您需要使用节点的序号位置,例如0是第一个节点。或节点的实际ID,例如“node-uuid-1234567890-1”。你正在尝试后者。阅读links.id api ref以选择您想要使用哪一个。在你的json中,你使用链接源和目标的数字。

如果综合这些点,这应该概率是根据你已做了你的重启逻辑,但你需要与你的ID用法一致:

simulation.nodes(nodes); 
    simulation.force("link").links(links); 
    simulation.alpha(1).restart(); 

看一看麦克block for updating a force layout是清楚你如何更新模拟。你正在做太多的工作

+0

谢谢!只是为了澄清,这是一个模拟的JSON,但它有源码和目标码,因为它正在通过Python的NetworkX。 –

+0

好的。所以在我看来,我在我的代码中跟随links.id API - 我通过使用它们的ID而不是索引来引用节点的每个链接。当我将它改变为默认行为时,我得到这个:'''未捕获的TypeError:无法在字符串'node-uuid-1234567890-2'上创建属性'vx' ''' –

+0

如果您使用字符串ID,则需要指定这样的链接力:var simulation = d3.forceSimulation() .force(“link”,d3.forceLink().id(function(d){return d.id;})),这样你的json链接是:{source:“node-uuid-1234567890-1”target:“node-uuid-1234567890-2”value:1}。vx是速度x的位置,它的基本意思是说,我无法弄清楚创建这个属性来移动你的节点/链接 – Robatron