2015-07-12 389 views
1

我正在尝试绘制与d3.js的力布局。我的JSON对象传递给D3使力布局具有正确的格式,但我得到以下错误:d3.js节点和边缘格式

TypeError: e[u.source.index] is undefined 

...++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.tar... 

注到E [u.source.index] .push(u.target)

我的JSON对象包含两个对象:

  1. 节点
  2. 边缘

节点是对象列表携带节点数据(即它可以是任何东西我所知)和边缘是对象的列表,指的节点目标对象性质

这是我代码段:

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

 
body { 
 
    font: 10px sans-serif; 
 
    shape-rendering: crispEdges; 
 
} 
 

 
.link.flow { 
 
    opacity: 1!important; 
 
    /*stroke-width: 1.5px;*/ 
 
} 
 

 
#licensing { 
 
    fill: green; 
 
} 
 

 
.link.flow.licensing { 
 
    stroke: green; 
 
} 
 

 
.link.flow.resolved { 
 
    stroke-dasharray: 0,2 1; 
 
} 
 

 
circle.flow { 
 
    fill: #ff2575; 
 
    stroke: #ff2575; 
 
    /*stroke-width: 1.5px;*/ 
 
} 
 

 
text.flow { 
 
    font: 10px sans-serif; 
 
    pointer-events: none; 
 
    text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff; 
 
} 
 

 
path.link.flow { 
 
    fill: none; 
 
} 
 

 

 

 

 
</style> 
 
<body> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> 
 
<script> 
 
var maxWeight = 0; 
 
var maxSize = 0; 
 

 
// new graph: start 
 
var margin = 10; 
 
var width = 455, 
 
\t height = 350; 
 

 
var svgMaster = d3.select("body").append("svg") // initiate svg 
 
\t .attr("id","flow") 
 
\t .attr("width", width) 
 
\t .attr("height", height) 
 
\t .style("margin-right",margin+"px") 
 
\t .style("margin-left",margin+"px"); 
 

 
var svg = svgMaster.append('svg:g') 
 
\t .attr('id','groupFlow'); 
 

 
var link = svg.selectAll(".link"), 
 
\t node = svg.selectAll(".node"); // nodes and links 
 
// :end new graph 
 

 
var jsonData = { 
 
\t "nodes": [ 
 
\t \t {"username": "S_Christophorus", "social_net_id": "55641120cdfa6618acdd1952", "last_name": 
 
\t \t "Christophorus", "first_name": "Stanly", "avatar": "/media/avatars/C02.png", "person_id": "556431f3cdfa661108325774" 
 
\t \t , "id": "55641120cdfa6618acdd1a8e"}, 
 
\t \t {"username": "A_Field", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Field", "first_name": "Abdul", "avatar": "/media/avatars/B01.png", "person_id": "556431f3cdfa6611083257f6" 
 
\t \t , "id": "55641120cdfa6618acdd1b94"}, 
 
\t \t {"username": "B_Hugh", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Hugh", "first_name": "Beale", "avatar": "/media/avatars/B02.png", "person_id": "556431f3cdfa6611083257f7" 
 
\t \t , "id": "55641120cdfa6618acdd1b96"}, 
 
\t \t {"username": "M_Kennedy", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Kennedy", "first_name": "Mordy", "avatar": "/media/avatars/B05.png", "person_id": "556431facdfa661108327e21" 
 
\t \t , "id": "55641128cdfa6618acdd9fed"} 
 
\t ], 
 
\t "edges": [ 
 
\t \t {"source": "0", "target": "1", "weight": 1.5}, 
 
\t \t {"source": "2", "target": "0", "weight": 46.5}, 
 
\t \t {"source": "0", "target": "2", "weight": 6.0}, 
 
\t \t {"source": "2", "target": "1", "weight": 1.5}, 
 
\t \t {"source": "2", "target": "3", "weight": 3.0} 
 
\t ] 
 
} 
 

 

 
/* 
 
* refresh graph based on given data 
 
*/ 
 
var refreshForceFlow = function(json){ 
 
\t clearGraphFlow(); 
 
\t var maxWeight = 0; 
 
\t 
 
    for(var edgeIndex = 0; edgeIndex < json.edges.length; edgeIndex++){ 
 
     if(json.edges[edgeIndex].weight > maxWeight) maxWeight = json.edges[edgeIndex]; 
 
     } 
 
\t console.log(json); 
 
\t var force = d3.layout.force() 
 
\t \t .nodes(d3.values(json.nodes)) 
 
\t \t .links(json.edges) 
 
\t \t .size([width, height]) 
 
\t \t .linkDistance(60) 
 
\t \t .charge(-300) 
 
\t \t .on("tick", tickFlow) 
 
\t \t .start(); 
 

 
\t // Per-type markers, as they don't inherit styles. 
 
\t svg.append("defs").selectAll("marker") 
 
\t \t .data(json.edges) 
 
\t \t .enter().append("marker") 
 
\t \t .attr("id", function(d) { return ("weight_"+d.weight).replace(".","_"); }) 
 
\t \t .attr("viewBox", "0 -5 10 10") 
 
\t \t .attr("refX", 13) // 15 
 
\t \t .attr("refY", 0) // -1.5 
 
\t \t .attr("markerWidth", 6) 
 
\t \t .attr("markerHeight", 6) 
 
\t \t .attr("orient", "auto") 
 
\t \t .append("path") 
 
\t \t .style("fill", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .style("stroke", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .style("stroke-width", "1px") 
 
\t \t .attr("d", "M0,-5L10,0L0,5"); 
 

 
\t var path = svg.append("g").selectAll("path") 
 
\t \t .data(force.links()) 
 
\t \t .enter().append("path") 
 
\t \t .attr("class", function(d) { return "link flow "; }) 
 
\t \t .style("stroke-width", function(d) { 
 
\t \t \t var res = 1 + ((d.weight * 2.5)/maxWeight); 
 
\t \t \t return res + 'px'; 
 
\t \t }) 
 
\t \t .style("stroke", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .attr("marker-end", function(d) { return "url(#" + ("weight_"+d.weight).replace(".","_") + ")"; }); 
 

 
\t var circle = svg.append("g").selectAll("circle") 
 
\t \t .data(force.nodes()) 
 
\t \t .enter().append("circle") 
 
\t \t .attr("r", 6) 
 
\t \t .attr("class", "flow") 
 
\t \t .on("contextmenu", d3.contextMenu(menu)) 
 
\t \t .call(force.drag); 
 

 
\t var text = svg.append("g").selectAll("text") 
 
\t \t .data(force.nodes()) 
 
\t \t .enter().append("text") 
 
\t \t .attr("class", "flow") 
 
\t \t .attr("x", 8) 
 
\t \t .attr("y", ".31em") 
 
\t \t .text(function(d) { return d.username; }); 
 

 
\t // Use elliptical arc path segments to doubly-encode directionality. 
 
\t function tickFlow() { 
 
\t \t path.attr("d", linkArc); 
 
\t \t circle.attr("transform", transform); 
 
\t \t text.attr("transform", transform); 
 
\t } 
 

 
\t function linkArc(d) { 
 
\t \t var tx = d.target.x - 0; 
 
\t \t var ty = d.target.y - 0; 
 
\t \t var sx = d.source.x - 0; 
 
\t \t var sy = d.source.y - 0; 
 

 
\t \t var dx = tx - sx, 
 
\t \t \t dy = ty - sy, 
 
\t \t \t dr = Math.sqrt(dx * dx + dy * dy); 
 
\t \t return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
 
\t } 
 

 
\t function transform(d) { 
 
\t \t return "translate(" + d.x + "," + d.y + ")"; 
 
\t } 
 
}; // end of function 
 

 
/* 
 
* clear gragh 
 
*/ 
 
var clearGraphFlow = function(){ 
 
\t svg.selectAll("g").remove(); 
 
\t svg.selectAll("defs").remove(); 
 
}; 
 

 
refreshForceFlow(jsonData); 
 

 
</script>

回答

2

,因为它们代表索引,您的边缘阵列的源和目标属性需要是数字而不是字符串。

"edges": [ 
    {"source": 0, "target": 1, "weight": 1.5}, 
    {"source": 2, "target": 0, "weight": 46.5}, 
    {"source": 0, "target": 2, "weight": 6.0}, 
    {"source": 2, "target": 1, "weight": 1.5}, 
    {"source": 2, "target": 3, "weight": 3.0} 
] 

这是工作:

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

 
body { 
 
    font: 10px sans-serif; 
 
    shape-rendering: crispEdges; 
 
} 
 

 
.link.flow { 
 
    opacity: 1!important; 
 
    /*stroke-width: 1.5px;*/ 
 
} 
 

 
#licensing { 
 
    fill: green; 
 
} 
 

 
.link.flow.licensing { 
 
    stroke: green; 
 
} 
 

 
.link.flow.resolved { 
 
    stroke-dasharray: 0,2 1; 
 
} 
 

 
circle.flow { 
 
    fill: #ff2575; 
 
    stroke: #ff2575; 
 
    /*stroke-width: 1.5px;*/ 
 
} 
 

 
text.flow { 
 
    font: 10px sans-serif; 
 
    pointer-events: none; 
 
    text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff; 
 
} 
 

 
path.link.flow { 
 
    fill: none; 
 
} 
 

 

 

 

 
</style> 
 
<body> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> 
 
<script> 
 
var maxWeight = 0; 
 
var maxSize = 0; 
 

 
// new graph: start 
 
var margin = 10; 
 
var width = 455, 
 
\t height = 350; 
 

 
var svgMaster = d3.select("body").append("svg") // initiate svg 
 
\t .attr("id","flow") 
 
\t .attr("width", width) 
 
\t .attr("height", height) 
 
\t .style("margin-right",margin+"px") 
 
\t .style("margin-left",margin+"px"); 
 

 
var svg = svgMaster.append('svg:g') 
 
\t .attr('id','groupFlow'); 
 

 
var link = svg.selectAll(".link"), 
 
\t node = svg.selectAll(".node"); // nodes and links 
 
// :end new graph 
 

 
var jsonData = { 
 
\t "nodes": [ 
 
\t \t {"username": "S_Christophorus", "social_net_id": "55641120cdfa6618acdd1952", "last_name": 
 
\t \t "Christophorus", "first_name": "Stanly", "avatar": "/media/avatars/C02.png", "person_id": "556431f3cdfa661108325774" 
 
\t \t , "id": "55641120cdfa6618acdd1a8e"}, 
 
\t \t {"username": "A_Field", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Field", "first_name": "Abdul", "avatar": "/media/avatars/B01.png", "person_id": "556431f3cdfa6611083257f6" 
 
\t \t , "id": "55641120cdfa6618acdd1b94"}, 
 
\t \t {"username": "B_Hugh", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Hugh", "first_name": "Beale", "avatar": "/media/avatars/B02.png", "person_id": "556431f3cdfa6611083257f7" 
 
\t \t , "id": "55641120cdfa6618acdd1b96"}, 
 
\t \t {"username": "M_Kennedy", "social_net_id": "55641120cdfa6618acdd1952" 
 
\t \t , "last_name": "Kennedy", "first_name": "Mordy", "avatar": "/media/avatars/B05.png", "person_id": "556431facdfa661108327e21" 
 
\t \t , "id": "55641128cdfa6618acdd9fed"} 
 
\t ], 
 
\t "edges": [ 
 
\t \t {"source": 0, "target": 1, "weight": 1.5}, 
 
\t \t {"source": 2, "target": 0, "weight": 46.5}, 
 
\t \t {"source": 0, "target": 2, "weight": 6.0}, 
 
\t \t {"source": 2, "target": 1, "weight": 1.5}, 
 
\t \t {"source": 2, "target": 3, "weight": 3.0} 
 
\t ] 
 
} 
 

 

 
/* 
 
* refresh graph based on given data 
 
*/ 
 
var refreshForceFlow = function(json){ 
 
\t clearGraphFlow(); 
 
\t var maxWeight = 0; 
 
\t 
 
    for(var edgeIndex = 0; edgeIndex < json.edges.length; edgeIndex++){ 
 
     if(json.edges[edgeIndex].weight > maxWeight) maxWeight = json.edges[edgeIndex]; 
 
     } 
 
\t console.log(json); 
 
\t var force = d3.layout.force() 
 
\t \t .nodes(d3.values(json.nodes)) 
 
\t \t .links(json.edges) 
 
\t \t .size([width, height]) 
 
\t \t .linkDistance(60) 
 
\t \t .charge(-300) 
 
\t \t .on("tick", tickFlow) 
 
\t \t .start(); 
 

 
\t // Per-type markers, as they don't inherit styles. 
 
\t svg.append("defs").selectAll("marker") 
 
\t \t .data(json.edges) 
 
\t \t .enter().append("marker") 
 
\t \t .attr("id", function(d) { return ("weight_"+d.weight).replace(".","_"); }) 
 
\t \t .attr("viewBox", "0 -5 10 10") 
 
\t \t .attr("refX", 13) // 15 
 
\t \t .attr("refY", 0) // -1.5 
 
\t \t .attr("markerWidth", 6) 
 
\t \t .attr("markerHeight", 6) 
 
\t \t .attr("orient", "auto") 
 
\t \t .append("path") 
 
\t \t .style("fill", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .style("stroke", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .style("stroke-width", "1px") 
 
\t \t .attr("d", "M0,-5L10,0L0,5"); 
 

 
\t var path = svg.append("g").selectAll("path") 
 
\t \t .data(force.links()) 
 
\t \t .enter().append("path") 
 
\t \t .attr("class", function(d) { return "link flow "; }) 
 
\t \t .style("stroke-width", function(d) { 
 
\t \t \t var res = 1 + ((d.weight * 2.5)/maxWeight); 
 
\t \t \t return res + 'px'; 
 
\t \t }) 
 
\t \t .style("stroke", function(d){ 
 
\t \t \t var color = 'FF'; 
 
\t \t \t var c = Math.floor((d.weight*99)/maxWeight); 
 
\t \t \t c = 100 - c; 
 
\t \t \t if(c < 10) c = '0'+c; 
 
\t \t \t color = c + color; 
 
\t \t \t color = c + color; 
 
\t \t \t //console.log('#'+color); 
 
\t \t \t return '#'+color; 
 
\t \t }) 
 
\t \t .attr("marker-end", function(d) { return "url(#" + ("weight_"+d.weight).replace(".","_") + ")"; }); 
 

 
\t var circle = svg.append("g").selectAll("circle") 
 
\t \t .data(force.nodes()) 
 
\t \t .enter().append("circle") 
 
\t \t .attr("r", 6) 
 
\t \t .attr("class", "flow") 
 
\t \t //.on("contextmenu", d3.contextMenu(menu)) 
 
\t \t .call(force.drag); 
 

 
\t var text = svg.append("g").selectAll("text") 
 
\t \t .data(force.nodes()) 
 
\t \t .enter().append("text") 
 
\t \t .attr("class", "flow") 
 
\t \t .attr("x", 8) 
 
\t \t .attr("y", ".31em") 
 
\t \t .text(function(d) { return d.username; }); 
 

 
\t // Use elliptical arc path segments to doubly-encode directionality. 
 
\t function tickFlow() { 
 
\t \t path.attr("d", linkArc); 
 
\t \t circle.attr("transform", transform); 
 
\t \t text.attr("transform", transform); 
 
\t } 
 

 
\t function linkArc(d) { 
 
\t \t var tx = d.target.x - 0; 
 
\t \t var ty = d.target.y - 0; 
 
\t \t var sx = d.source.x - 0; 
 
\t \t var sy = d.source.y - 0; 
 

 
\t \t var dx = tx - sx, 
 
\t \t \t dy = ty - sy, 
 
\t \t \t dr = Math.sqrt(dx * dx + dy * dy); 
 
\t \t return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
 
\t } 
 

 
\t function transform(d) { 
 
\t \t return "translate(" + d.x + "," + d.y + ")"; 
 
\t } 
 
}; // end of function 
 

 
/* 
 
* clear gragh 
 
*/ 
 
var clearGraphFlow = function(){ 
 
\t svg.selectAll("g").remove(); 
 
\t svg.selectAll("defs").remove(); 
 
}; 
 

 
refreshForceFlow(jsonData); 
 

 
</script>

+0

哦谢谢!它工作正常:) @Mark – rezCash