我需要创建一个强制定向布局,可以像example一样进行更新。
另一方面,我需要在边缘使用标签的力布局以及每个边缘末端的箭头。为此,我尝试将此example与前一个{{3}}结合起来。
因此,为了使标签位于边缘和箭头中,我使用第二个示例的path
。
到目前为止,这是我的代码:
<!DOCTYPE html>
<html>
<head>
<title>Animating Changes in Force Diagram</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<style>
.link {
stroke: #2E2E2E;
stroke-width: 2px;
}
.node {
stroke: #fff;
stroke-width: 2px;
}
.textClass {
stroke: #323232;
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
font-weight: normal;
stroke-width: .5;
font-size: 14px;
}
.edgepath {
stroke: #323232;
font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif;
font-weight: normal;
stroke-width: .5;
font-size: 14px;
}
.aEnd{
fill: #444;
font-family: helvetica;
font-size: 8pt;
}
</style>
</head>
<body>
<button onclick="addNodes()">Restart Animation</button>
<button onclick="addNode1()">Test</button>
<script>
var graph;
function myGraph() {
// Add and remove elements on the graph object
this.addNode = function (id) {
nodes.push({"id": id});
update();
};
this.removeNode = function (id) {
var i = 0;
var n = findNode(id);
while (i < links.length) {
if ((links[i]['source'] == n) || (links[i]['target'] == n)) {
links.splice(i, 1);
}
else i++;
}
nodes.splice(findNodeIndex(id), 1);
update();
};
this.removeLink = function (source, target) {
for (var i = 0; i < links.length; i++) {
if (links[i].source.id == source && links[i].target.id == target) {
links.splice(i, 1);
break;
}
}
update();
};
this.removeallLinks = function () {
links.splice(0, links.length);
update();
};
this.removeAllNodes = function () {
nodes.splice(0, links.length);
update();
};
this.addLink = function (source, target, value) {
links.push({"source": findNode(source), "target": findNode(target), "value": value});
update();
};
var findNode = function (id) {
for (var i in nodes) {
if (nodes[i]["id"] === id) return nodes[i];
}
;
};
var findNodeIndex = function (id) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].id == id) {
return i;
}
}
;
};
// set up the D3 visualisation in the specified element
var w = 960, h = 450;
var color = d3.scale.category10();
var vis = d3.select("body")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("id", "svg")
.attr("pointer-events", "all")
.attr("viewBox", "0 0 " + w + " " + h)
.attr("perserveAspectRatio", "xMinYMid")
.append('svg:g');
var force = d3.layout.force();
var nodes = force.nodes();
var links = force.links();
var update = function () {
var link = vis.selectAll("line")
.data(links, function (d) {
return d.source.id + "-" + d.target.id;
});
link.enter().append("line")
.attr("id", function (d) {
return d.source.id + "-" + d.target.id;
})
.attr('marker-end','url(#arrowhead)')
.style("stroke","#ccc")
.style("pointer-events", "none");
link.exit().remove();
var edgepaths = svg.selectAll(".edgepath")
.data(links)
.enter()
.append('path')
.attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
'class':'edgepath',
'fill-opacity':0,
'stroke-opacity':0,
'fill':'blue',
'stroke':'red',
'id':function(d,i) {return 'edgepath'+i}})
.style("pointer-events", "none");
var node = vis.selectAll("g.node")
.data(nodes, function (d) {
return d.id;
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.call(force.drag);
nodeEnter.append("svg:circle")
.attr("r", 12)
.attr("id", function (d) {
return "Node;" + d.id;
})
.attr("class", "nodeStrokeClass")
.attr("fill", function(d) { return color(d.id); });
nodeEnter.append("svg:text")
.attr("class", "textClass")
.attr("x", 14)
.attr("y", ".31em")
.text(function (d) {
return d.id;
});
node.exit().remove();
force.on("tick", function () {
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
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;
});
});
// Restart the force layout.
force
.gravity(.01)
.charge(-80000)
.friction(0)
.linkDistance( function(d) { return d.value * 10 } )
.size([w, h])
.start();
};
// Make it all go
update();
}
function drawGraph() {
graph = new myGraph("#svgdiv");
graph.addNode('Sophia');
graph.addNode('Ryan');
graph.addNode('Alex');
graph.addNode('Daniel');
graph.addNode('Too');
graph.addLink('Alex', 'Ryan', '20');
graph.addLink('Sophia', 'Ryan', '20');
graph.addLink('Daniel', 'Ryan', '20');
graph.addLink('Daniel', 'Too', '20');
keepNodesOnTop();
}
drawGraph();
// because of the way the network is created, nodes are created first, and links second,
// so the lines were on top of the nodes, this just reorders the DOM to put the svg:g on top
function keepNodesOnTop() {
$(".nodeStrokeClass").each(function( index ) {
var gnode = this.parentNode;
gnode.parentNode.appendChild(gnode);
});
}
function addNodes() {
d3.select("svg")
.remove();
drawGraph();
}
function addNode1() {
d3.select("svg")
.remove();
drawGraph();
graph.addNode('Test1');
graph.addNode('Test2');
graph.addLink('Test1', 'Test2', '20');
keepNodesOnTop();
}
</script>
</body>
</html>
选择问题和path
显示此错误:
Uncaught TypeError: svg.selectAll is not a function at update (combine2.html:148)
因为这行代码:
var edgepaths = svg.selectAll(".edgepath")
答案 0 :(得分:2)
未定义对象svg
。你还没有创建它。但是您确实有一个对象vis
,您可以在其中附加链接:
var link = vis.selectAll("line")...
Vis
是你的svg的选择,所以你需要将你的svg元素附加到它:
var vis = d3.select("body")
.append("svg:svg")
对于你的edgepaths,试试:
var edgepaths = vis.selectAll(".edgepath")...
而不是:
var edgepaths = svg.selectAll(".edgepath")...