2017-07-15 183 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