2017-03-25 10 views
0

を働いていない私は視覚化するには、次の簡単なグラフを持っている:D3は、クリックすることにより、力のネットワークを拡大 -

sample graph

のみ「N1」まずが、その隣人N2 "

第二に接続されているように'n2'をクリックするとネットワークは2つのエッジ 'n3'と 'n2' - > 'n4'を追加して展開されます

第3に、 'n3'をクリックすると、 2つのエッジ 'n3' - > 'n1'と 'n3' - > 'n5'

これを行うには、私は見えるノードの配列を作成できると思った。ノードをクリックすると、このノード名がアレイに追加されます。そしてtick()関数では、その配列の可視ノードがネットワークの設定に使用されます。

しかし、私は次のコードでそれを行うとき:

// return currently visible nodes as the source nodes 
// e.g. called by 
// var visible_seeds = seeding(nodes); 
// 
function seeding(nodes){ 
    var visible = []; 
    nodes.forEach(function(n){ 
     if(n.name=='n1') 
     visible.push(n); 
    }); 
    return visible; 
} 

上記の機能は、次のように呼ばれている:

var visible_seeds = seeding(nodes); 

var force = d3.layout.force() 
.nodes(d3.values(visible_seeds)) 
.links(links) 
.size([width, height]) 
.linkDistance(60) 
.charge(-300) 
.on("tick", tick) 
.start(); 

それが何であるか、エラーに

index.html TypeError:'undefined' is not a function (evaluating 'nodes.forEach(function(n){...')

を与えます私の目標を達成する正しい方法は?ありがとうございました!

P.S.私はD3とjavascriptに全く新しいです。

csvファイルからあるデータはD3で読み込ま: http://bl.ocks.org/d3noob/5155181

を追加しました - ソースコード - 問題はで起こる:私のコードはで例に基づいて

source,target,value 
n1,n2,1.0 
n2,n3,1.0 
n2,n4,1.0 
n3,n1,1.0 
n3,n5,1.0 

function seeding()

<!DOCTYPE html> 
<meta charset="utf-8"> 
<script src="http://d3js.org/d3.v3.js"></script> 
<style> 

path.link { 
    fill: none; 
    stroke: #666; 
    stroke-width: 1.5px; 
} 

path.link.twofive { 
    opacity: 0.25; 
} 

path.link.fivezero { 
    opacity: 0.50; 
} 

path.link.sevenfive { 
    opacity: 0.75; 
} 

path.link.onezerozero { 
    opacity: 1.0; 
} 

circle { 
    fill: #ccc; 
    stroke: #fff; 
    stroke-width: 1.5px; 
} 

text { 
    fill: #000; 
    font: 10px sans-serif; 
    pointer-events: none; 
} 

</style> 
<body> 
<script> 


// get the data 
d3.csv("force.csv", function(error, links) { 

var nodes = {}; 

// Compute the distinct nodes from the links. 
links.forEach(function(link) { 
    link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, vis:0}); 
    link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, vis:0}); 
    link.value = +link.value; 
}); 

//nodes["n1"] = {name:"n1", vis:1}; 
var vis = ['n1']; 

var width = 960, 
    height = 500; 

function seeding(){ 
var visible = []; 
nodes.forEach(function(n){ 
    if(n.name=='n1') 
     visible.push(n); 
}); 
return visible; 
} 

var visible_seeds = seeding(); 

var force = d3.layout.force() 
    .nodes(d3.values(visible_seeds)) 
    //.nodes(d3.values(nodes)) 
    .links(links) 
    .size([width, height]) 
    .linkDistance(60) 
    .charge(-300) 
    .on("tick", tick) 
    .start(); 

// Set the range 
var v = d3.scale.linear().range([0, 100]); 

// Scale the range of the data 
v.domain([0, d3.max(links, function(d) { return d.value; })]); 

// asign a type per value to encode opacity 
links.forEach(function(link) { 
    if (v(link.value) <= 25) { 
     link.type = "twofive"; 
    } else if (v(link.value) <= 50 && v(link.value) > 25) { 
     link.type = "fivezero"; 
    } else if (v(link.value) <= 75 && v(link.value) > 50) { 
     link.type = "sevenfive"; 
    } else if (v(link.value) <= 100 && v(link.value) > 75) { 
     link.type = "onezerozero"; 
    } 
}); 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

// 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"); 

// add the links and the arrows 
var path = svg.append("svg:g").selectAll("path") 
    .data(force.links()) 
    .enter().append("svg:path") 
    .attr("class", function(d) { return "link " + d.type; }) 
    .attr("marker-end", "url(#end)"); 

// define the nodes 
var node = svg.selectAll(".node") 
    .data(force.nodes()) 
    .enter().append("g") 
    .attr("class", "node") 
    .on("click", click) 
    .on("dblclick", dblclick) 
    .call(force.drag); 

// add the nodes 
node.append("circle") 
    .attr("r", 5); 

// add the text 
node.append("text") 
    .attr("x", 12) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name; }); 

// add the curvy lines 
function tick() { 
    path.attr("d", function(d) { 
     var dx = d.target.x - d.source.x, 
      dy = d.target.y - d.source.y, 
      dr = Math.sqrt(dx * dx + dy * dy); 
     return "M" + 
      d.source.x + "," + 
      d.source.y + "A" + 
      dr + "," + dr + " 0 0,1 " + 
      d.target.x + "," + 
      d.target.y; 
    }); 

    node 
     .attr("transform", function(d) { 
      return "translate(" + d.x + "," + d.y + ")"; }); 
} 

// action to take on mouse click 
function click() { 
    d3.select(this).select("text").transition() 
     .duration(750) 
     .attr("x", 22) 
     .style("fill", "steelblue") 
     .style("stroke", "lightsteelblue") 
     .style("stroke-width", ".5px") 
     .style("font", "20px sans-serif"); 
    d3.select(this).select("circle").transition() 
     .duration(750) 
     .attr("r", 16) 
     .style("fill", "lightsteelblue"); 
} 

// action to take on mouse double click 
function dblclick() { 
    d3.select(this).select("circle").transition() 
     .duration(750) 
     .attr("r", 6) 
     .style("fill", "#ccc"); 
    d3.select(this).select("text").transition() 
     .duration(750) 
     .attr("x", 12) 
     .style("stroke", "none") 
     .style("fill", "black") 
     .style("stroke", "none") 
     .style("font", "10px sans-serif"); 
} 

}); 

</script> 
</body> 
</html> 
+0

'TypeError例外: '未定義のは' function'は、ノードは**ない** JavaScript配列であることを意味しません。 'd3'を選択した場合は' nodes.each(function ...) 'を試してください。そうでなければもっとコードを表示する必要があります。 – Mark

+0

コメントありがとうございます!コードが質問に追加されます。 – askmeasku

答えて

0

最初に、エラーの原因はnodesはJavaScriptオブジェクト(配列ではありません)です。forEachメソッドはありません。

第2に、私はあなたのアプローチにどこに行くのかは分かりません。あなたは1つのノードでフォースレイアウトを開始しますクリックすると他のノードが追加されますか?どのようにリンクを処理するつもりですか?

Intead、私はちょうどクリック時のノードとリンクの可視性をトグルすることをお勧めします。ここでは簡単な実装です:

<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<script src="http://d3js.org/d3.v3.js"></script> 
 
<style> 
 

 
path.link { 
 
    fill: none; 
 
    stroke: #666; 
 
    stroke-width: 1.5px; 
 
} 
 

 
path.link.twofive { 
 
    opacity: 0.25; 
 
} 
 

 
path.link.fivezero { 
 
    opacity: 0.50; 
 
} 
 

 
path.link.sevenfive { 
 
    opacity: 0.75; 
 
} 
 

 
path.link.onezerozero { 
 
    opacity: 1.0; 
 
} 
 

 
circle { 
 
    fill: #ccc; 
 
    stroke: #fff; 
 
    stroke-width: 1.5px; 
 
} 
 

 
text { 
 
    fill: #000; 
 
    font: 10px sans-serif; 
 
    pointer-events: none; 
 
} 
 

 
</style> 
 
<body> 
 
<script> 
 

 

 
// get the data 
 
//d3.csv("force.csv", function(error, links) { 
 

 
var links = [{"source":"n1","target":"n2","value":"1.0"},{"source":"n2","target":"n3","value":"1.0"},{"source":"n2","target":"n4","value":"1.0"},{"source":"n3","target":"n1","value":"1.0"},{"source":"n3","target":"n5","value":"1.0 "}]; 
 

 
var nodes = {}; 
 

 
// Compute the distinct nodes from the links. 
 
links.forEach(function(link) { 
 
    link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, vis:0}); 
 
    link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, vis:0}); 
 
    link.value = +link.value; 
 
}); 
 

 
//nodes["n1"] = {name:"n1", vis:1}; 
 
var vis = ['n1']; 
 

 
var width = 300, 
 
    height = 300; 
 

 
for (key in nodes){ 
 
    var node = nodes[key]; 
 
    node.visible = (node.name === 'n1'); 
 
} 
 

 
var force = d3.layout.force() 
 
    .nodes(d3.values(nodes)) 
 
    .links(links) 
 
    .size([width, height]) 
 
    .linkDistance(60) 
 
    .charge(-300) 
 
    .on("tick", tick) 
 
    .start(); 
 

 
// Set the range 
 
var v = d3.scale.linear().range([0, 100]); 
 

 
// Scale the range of the data 
 
v.domain([0, d3.max(links, function(d) { return d.value; })]); 
 

 
// asign a type per value to encode opacity 
 
links.forEach(function(link) { 
 
    if (v(link.value) <= 25) { 
 
     link.type = "twofive"; 
 
    } else if (v(link.value) <= 50 && v(link.value) > 25) { 
 
     link.type = "fivezero"; 
 
    } else if (v(link.value) <= 75 && v(link.value) > 50) { 
 
     link.type = "sevenfive"; 
 
    } else if (v(link.value) <= 100 && v(link.value) > 75) { 
 
     link.type = "onezerozero"; 
 
    } 
 
}); 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", width) 
 
    .attr("height", height); 
 

 
// 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"); 
 

 
// add the links and the arrows 
 
var path = svg.append("svg:g").selectAll("path") 
 
    .data(force.links()) 
 
    .enter().append("svg:path") 
 
    .attr("class", function(d) { return "link " + d.type; }) 
 
    .attr("marker-end", "url(#end)") 
 
    .style("opacity", function(d){ 
 
     return d.target.visible && d.source.visible ? 1 : 0; 
 
    }) 
 

 
// define the nodes 
 
var node = svg.selectAll(".node") 
 
    .data(force.nodes()) 
 
    .enter().append("g") 
 
    .attr("class", "node") 
 
    .style("opacity", function(d){ 
 
     return d.visible ? 1 : 0; 
 
    }) 
 
    .on("click", click) 
 
    .call(force.drag); 
 

 
// add the nodes 
 
node.append("circle") 
 
    .attr("r", 5); 
 

 
// add the text 
 
node.append("text") 
 
    .attr("x", 12) 
 
    .attr("dy", ".35em") 
 
    .text(function(d) { return d.name; }); 
 

 
// add the curvy lines 
 
function tick() { 
 
    path.attr("d", function(d) { 
 
     var dx = d.target.x - d.source.x, 
 
      dy = d.target.y - d.source.y, 
 
      dr = Math.sqrt(dx * dx + dy * dy); 
 
     return "M" + 
 
      d.source.x + "," + 
 
      d.source.y + "A" + 
 
      dr + "," + dr + " 0 0,1 " + 
 
      d.target.x + "," + 
 
      d.target.y; 
 
    }); 
 

 
    node 
 
     .attr("transform", function(d) { 
 
      return "translate(" + d.x + "," + d.y + ")"; }); 
 
} 
 

 
// action to take on mouse click 
 
function click(d0) { 
 
    links.forEach(function(d1){ 
 
    console.log(d0, d1.source) 
 
    if (d1.source === d0) { 
 
     d1.target.visible = !d1.target.visible; 
 
    } 
 
    }); 
 
    node.style("opacity", function(d){ 
 
    return d.visible ? 1 : 0; 
 
    }); 
 
    path.style("opacity", function(d){ 
 
    return d.target.visible && d.source.visible ? 1 : 0; 
 
    }); 
 
} 
 

 
//}); 
 

 
</script> 
 
</body> 
 
</html>

+0

Markありがとう、あなたはそれをほぼ解決しました。私が望むのは、グラフをインクリメンタルに表示(拡大)することです。ノードが5つではなく5000個あることを想像してください。すべてが遅いかもしれないので、1つのノードから始めたいと思います。これをクリックすることにより、隣接するノードとそれらの間のリンクをロードします。隣接ノードの1つをクリックすると、新しい隣接ノードとエッジが追加されます。 – askmeasku

関連する問題