我正在尝试使用 d3.js 绘制力布局。我的json对象传递给d3以使强制布局具有正确的格式,但我得到以下错误:
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对象包含两个对象:
节点是承载节点数据的对象列表(可能是我所知道的任何事情),而edge是一个对象列表,它引用 source 和 target <中的节点对象/ em> properties
这是我的代码段:
<!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,
height = 350;
var svgMaster = d3.select("body").append("svg") // initiate svg
.attr("id","flow")
.attr("width", width)
.attr("height", height)
.style("margin-right",margin+"px")
.style("margin-left",margin+"px");
var svg = svgMaster.append('svg:g')
.attr('id','groupFlow');
var link = svg.selectAll(".link"),
node = svg.selectAll(".node"); // nodes and links
// :end new graph
var jsonData = {
"nodes": [
{"username": "S_Christophorus", "social_net_id": "55641120cdfa6618acdd1952", "last_name":
"Christophorus", "first_name": "Stanly", "avatar": "/media/avatars/C02.png", "person_id": "556431f3cdfa661108325774"
, "id": "55641120cdfa6618acdd1a8e"},
{"username": "A_Field", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Field", "first_name": "Abdul", "avatar": "/media/avatars/B01.png", "person_id": "556431f3cdfa6611083257f6"
, "id": "55641120cdfa6618acdd1b94"},
{"username": "B_Hugh", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Hugh", "first_name": "Beale", "avatar": "/media/avatars/B02.png", "person_id": "556431f3cdfa6611083257f7"
, "id": "55641120cdfa6618acdd1b96"},
{"username": "M_Kennedy", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Kennedy", "first_name": "Mordy", "avatar": "/media/avatars/B05.png", "person_id": "556431facdfa661108327e21"
, "id": "55641128cdfa6618acdd9fed"}
],
"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}
]
}
/*
* refresh graph based on given data
*/
var refreshForceFlow = function(json){
clearGraphFlow();
var maxWeight = 0;
for(var edgeIndex = 0; edgeIndex < json.edges.length; edgeIndex++){
if(json.edges[edgeIndex].weight > maxWeight) maxWeight = json.edges[edgeIndex];
}
console.log(json);
var force = d3.layout.force()
.nodes(d3.values(json.nodes))
.links(json.edges)
.size([width, height])
.linkDistance(60)
.charge(-300)
.on("tick", tickFlow)
.start();
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(json.edges)
.enter().append("marker")
.attr("id", function(d) { return ("weight_"+d.weight).replace(".","_"); })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 13) // 15
.attr("refY", 0) // -1.5
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.style("fill", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.style("stroke", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.style("stroke-width", "1px")
.attr("d", "M0,-5L10,0L0,5");
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link flow "; })
.style("stroke-width", function(d) {
var res = 1 + ((d.weight * 2.5) / maxWeight);
return res + 'px';
})
.style("stroke", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.attr("marker-end", function(d) { return "url(#" + ("weight_"+d.weight).replace(".","_") + ")"; });
var circle = svg.append("g").selectAll("circle")
.data(force.nodes())
.enter().append("circle")
.attr("r", 6)
.attr("class", "flow")
.on("contextmenu", d3.contextMenu(menu))
.call(force.drag);
var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text")
.attr("class", "flow")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.username; });
// Use elliptical arc path segments to doubly-encode directionality.
function tickFlow() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}
function linkArc(d) {
var tx = d.target.x - 0;
var ty = d.target.y - 0;
var sx = d.source.x - 0;
var sy = d.source.y - 0;
var dx = tx - sx,
dy = ty - sy,
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;
}
function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}
}; // end of function
/*
* clear gragh
*/
var clearGraphFlow = function(){
svg.selectAll("g").remove();
svg.selectAll("defs").remove();
};
refreshForceFlow(jsonData);
</script>
答案 0 :(得分:2)
由于它们表示索引,因此edge数组的源和目标属性需要是数字而不是字符串。
"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,
height = 350;
var svgMaster = d3.select("body").append("svg") // initiate svg
.attr("id","flow")
.attr("width", width)
.attr("height", height)
.style("margin-right",margin+"px")
.style("margin-left",margin+"px");
var svg = svgMaster.append('svg:g')
.attr('id','groupFlow');
var link = svg.selectAll(".link"),
node = svg.selectAll(".node"); // nodes and links
// :end new graph
var jsonData = {
"nodes": [
{"username": "S_Christophorus", "social_net_id": "55641120cdfa6618acdd1952", "last_name":
"Christophorus", "first_name": "Stanly", "avatar": "/media/avatars/C02.png", "person_id": "556431f3cdfa661108325774"
, "id": "55641120cdfa6618acdd1a8e"},
{"username": "A_Field", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Field", "first_name": "Abdul", "avatar": "/media/avatars/B01.png", "person_id": "556431f3cdfa6611083257f6"
, "id": "55641120cdfa6618acdd1b94"},
{"username": "B_Hugh", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Hugh", "first_name": "Beale", "avatar": "/media/avatars/B02.png", "person_id": "556431f3cdfa6611083257f7"
, "id": "55641120cdfa6618acdd1b96"},
{"username": "M_Kennedy", "social_net_id": "55641120cdfa6618acdd1952"
, "last_name": "Kennedy", "first_name": "Mordy", "avatar": "/media/avatars/B05.png", "person_id": "556431facdfa661108327e21"
, "id": "55641128cdfa6618acdd9fed"}
],
"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}
]
}
/*
* refresh graph based on given data
*/
var refreshForceFlow = function(json){
clearGraphFlow();
var maxWeight = 0;
for(var edgeIndex = 0; edgeIndex < json.edges.length; edgeIndex++){
if(json.edges[edgeIndex].weight > maxWeight) maxWeight = json.edges[edgeIndex];
}
console.log(json);
var force = d3.layout.force()
.nodes(d3.values(json.nodes))
.links(json.edges)
.size([width, height])
.linkDistance(60)
.charge(-300)
.on("tick", tickFlow)
.start();
// Per-type markers, as they don't inherit styles.
svg.append("defs").selectAll("marker")
.data(json.edges)
.enter().append("marker")
.attr("id", function(d) { return ("weight_"+d.weight).replace(".","_"); })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 13) // 15
.attr("refY", 0) // -1.5
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.style("fill", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.style("stroke", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.style("stroke-width", "1px")
.attr("d", "M0,-5L10,0L0,5");
var path = svg.append("g").selectAll("path")
.data(force.links())
.enter().append("path")
.attr("class", function(d) { return "link flow "; })
.style("stroke-width", function(d) {
var res = 1 + ((d.weight * 2.5) / maxWeight);
return res + 'px';
})
.style("stroke", function(d){
var color = 'FF';
var c = Math.floor((d.weight*99)/maxWeight);
c = 100 - c;
if( c < 10) c = '0'+c;
color = c + color;
color = c + color;
//console.log('#'+color);
return '#'+color;
})
.attr("marker-end", function(d) { return "url(#" + ("weight_"+d.weight).replace(".","_") + ")"; });
var circle = svg.append("g").selectAll("circle")
.data(force.nodes())
.enter().append("circle")
.attr("r", 6)
.attr("class", "flow")
//.on("contextmenu", d3.contextMenu(menu))
.call(force.drag);
var text = svg.append("g").selectAll("text")
.data(force.nodes())
.enter().append("text")
.attr("class", "flow")
.attr("x", 8)
.attr("y", ".31em")
.text(function(d) { return d.username; });
// Use elliptical arc path segments to doubly-encode directionality.
function tickFlow() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}
function linkArc(d) {
var tx = d.target.x - 0;
var ty = d.target.y - 0;
var sx = d.source.x - 0;
var sy = d.source.y - 0;
var dx = tx - sx,
dy = ty - sy,
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;
}
function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}
}; // end of function
/*
* clear gragh
*/
var clearGraphFlow = function(){
svg.selectAll("g").remove();
svg.selectAll("defs").remove();
};
refreshForceFlow(jsonData);
</script>
&#13;