我正在尝试创建一个交互式图表。为此,我想点击两个节点并创建一个链接(稍后我想删除一个链接,如果它存在)。
我跟随迈克博斯托克的例子: https://bl.ocks.org/mbostock/1095795
我添加了这个功能:
function changeLink() {
if (nodeobjList.length < 1) {
nodeobjList.push(nodeobj)
} else if (nodeobjList.length == 1) {
nodeobjList.push(nodeobj)
firstnode = nodeobjList[0]
secondnode = nodeobjList[1]
graphLinks.push({source: firstnode.id, target: secondnode.id, value: 1 });
console.log(graphLinks)
// Apply the general update pattern to the links.
link = link.data(graphLinks, function(d) { return firstnode.id + "-" + secondnode.id; });
link.exit().remove();
link = link.enter().append("line").merge(link);
// Update and restart the simulation.
simulation.nodes(nodes);
simulation.force("link").links(link);
simulation.alpha(1).restart();
}
}
这会产生错误:
"Uncaught TypeError: Cannot create property 'vx' on string 'MotherPlutarch'"
所以我用对象替换了id,如:
graphLinks.push({source: firstnode, target: secondnode, value: 1 });
这次图表的所有点都移动到左上角。 错误是:
Error: <line> attribute x1: Expected length, "NaN".
我可以通过鼠标位置获取行的开头和结尾的x,y坐标,或者通过id过滤节点。但由于节点都在向左上角移动,我怀疑一些更复杂的错误或缺失。
有人知道发生了什么吗? 提前谢谢了, 马库斯
有关详细信息,请在此处添加完整的html文件:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var defs = svg.append('defs');
defs.append("pattern")
.attr("x", 0)
.attr("y", 0)
.attr("width", 1)
.attr("height", 1)
.attr("id", "test")
.append("image")
.attr("xlink:href", 'https://assets-cdn.github.com/images/modules/open_graph/github-octocat.png')
.attr("width", 100)
.attr("height", 60)
.attr("x", -30)
.attr("y", -10);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
var node;
var link;
var graphNodes;
var graphLinks;
var nodeobjList = [];
var nodeobj;
d3.json("miserables.json", function(error, graph) {
if (error) throw error;
// 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", 13)
.attr("refY", 0)
.attr("markerWidth", 9)
.attr("markerHeight", 9)
.attr("orient", "auto")
.attr("xoverflow",'visible')
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.attr('fill', '#999')
.style('stroke','none');
link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return Math.sqrt(d.value); })
.attr("marker-end", "url(#end)");
graphLinks = graph.links
graphNodes = graph.nodes
node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 20)
.on("click", function(d){
d3.select(this).attr("fill", "url(#test)")
})
.on("dblclick", function(d){
nodeobj = d
changeLink();
})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
node.append("title")
.text(function(d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
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; });
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
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 changeLink() {
if (nodeobjList.length < 1) {
nodeobjList.push(nodeobj)
} else if (nodeobjList.length == 1) {
nodeobjList.push(nodeobj)
firstnode = nodeobjList[0]
secondnode = nodeobjList[1]
graphLinks.push({source: firstnode, target: secondnode, value: 1 });
console.log(graphLinks)
// Apply the general update pattern to the links.
link = link.data(graphLinks, function(d) { return firstnode + "-" + secondnode; });
link.exit().remove();
link = link.enter().append("line").merge(link);
// Update and restart the simulation.
simulation.nodes(nodes);
simulation.force("link").links(link);
simulation.alpha(1).restart();
}
}
</script>`
答案 0 :(得分:0)
这里有很多错误
更新模拟时引用错误的数组
simulation.nodes(节点); simulation.force( “链接”)的链路(链路);
节点和链接都应该引用graphNodes和graphLinks数组
您应该在创建新链接后清除nodeobjList数组,例如
nodeobjList = []
例如,您更新的代码可能如下所示,这更像是您引用的Bostock示例:
function changeLink() {
if (nodeobjList.length < 1) {
nodeobjList.push(nodeobj)
} else if (nodeobjList.length == 1) {
nodeobjList.push(nodeobj)
firstnode = nodeobjList[0].id
secondnode = nodeobjList[1].id
graphLinks.push({source: firstnode, target: secondnode, value: 1 });
nodeobjList = []
restart();
}
}
function restart() {
link = link.data(graphLinks, function(d) { return firstnode + "-" + secondnode; });
link.exit().remove();
link = link.enter().append("line").merge(link);
// Update and restart the simulation.
simulation.force("link").links(graphLinks);
simulation.alpha(1).restart();
}