我是D3版本4的新用户,我在向强制定向布局中添加固定节点功能时遇到了问题。我相信这是通过将d.fixed设置为true在v3中实现的,但是我将此问题转换为与v4兼容的问题。我已经尝试添加simulation.fix,但是如果不从模拟开始修复节点,就无法将其集成到我现有的代码中。
理想情况下,我想添加一个双击侦听器,它可以将节点固定到位,并允许它通过拖动功能定位,然后再次双击时恢复模拟力。提前感谢您的帮助。
这是我的js:
<!--load svg-->
<svg width="1500" height="600"></svg>
<!--begin javascript for d3 forced layout-->
<script>
var svgNetwork = d3.select("svg"),
width = +svgNetwork.attr("width"),
height = +svgNetwork.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(data1) { return data1.id; }))
.force("charge", d3.forceManyBody().strength(-1500))
.force("center", d3.forceCenter(width / 2, height / 2));
//load the node csv data and link csv data together - open node(open link(funtions for making chart))
d3.csv("nodes.csv", function (error1, data1) {
if (error1) throw error1;
console.log(data1);
d3.csv("lines.csv", function (error2, data2) {
if (error2) throw error2;
console.log(data2);
data1.forEach(function (data1){
data1.group = +data1.group;
});
var lower = d3.min(data1, function(data1) {return data1.group;});
var upper = d3.max(data1, function(data1) {return data1.group;});
var color = d3.scaleLinear()
.domain([lower, 0, upper])
.range(["#2E64FE", "#E6E6E6", "red"]);
var link = svgNetwork.append("g")
.attr("class", "links")
.selectAll("line")
.data(data2)
.enter()
.append("line")
.attr("stroke-width", function(data2) { return Math.sqrt(data2.value); })
.attr("fill", "#777")
.attr("stroke-opacity", "0.6");
var node = svgNetwork.selectAll(".node")
.data(data1)
.enter()
.append("g");
var circle = node.append("circle")
.attr("id", function(data1) {return data1.id;})
.attr("r", function(data1) {return data1.rad;})
.attr("fill", function(data1) { return color(data1.group); })
.style("stroke", function(data1) { return color(data1.group); })
.style("stroke-width", "10px")
.style("stroke-opacity", "0.9");
var label = node.append("svg:text")
.text(function (data1) { return data1.id; })
.style("text-anchor", "middle")
.style("fill", "#000000")
.style("font-family", "Arial")
.style("font-size", "0.8em")
.style("font-weight", "bold");
node.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
simulation
.nodes(data1)
.on("tick", ticked);
simulation.force("link")
.links(data2);
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("transform", function(d) { return "translate(" + d.x + "," + 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;
}
以下是我的node.csv文件和lines.csv文件的示例:
id group rad
a 0.168316947 0.288907878
b -0.38499088 1.012210504
c -0.548386797 1.301376974
d -0.215565786 2.456429671
e -0.756094177 6.409396582
f -0.538867892 1.804950731
g -0.325232806 0.518895927
h 0.686157994 1.011850971
i -0.723155438 5.853700074
j 2.008089674 2.73207752
k -0.358621917 2.040722107
l -0.393305984 3.221637083
m -0.676289998 1.598250699
n -0.950808451 26.26021586
o 0.134589658 0.270633823
p -0.521333199 6.216421369
q 1.628300116 2.293471337
r 0.62673 2
s -0.843711093 40.86067523
source target value
b a 20
c a 20
d a 20
e a 20
f a 20
g a 20
h a 20
i a 20
j a 20
k a 20
l a 20
m a 20
n a 20
o a 20
p a 20
q a 20
r a 20
s a 20
答案 0 :(得分:15)
不确定是否需要答案,但我能够使节点变得粘滞,实际上在您的代码中修复非常简单,我在GitHub上查看此问题时学到了它 - Issue #35
现在在d3库的v4中修复节点的想法非常简单,在上面的代码中只需注释两行:
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
//d.fx = null;
//d.fy = null;
}
理论是,为了修复节点,我们需要设置node.fx
&amp;您的代码实际在node.fy
函数定义中设置的dragged()
。
希望它对我有所帮助。
此处的文档中也提到了相同的内容 - D3 V4 - API
要将节点固定在给定位置,您可以指定另外两个节点 属性:
fx
- 节点的固定x位置fy
- 节点的固定y位置
答案 1 :(得分:4)
另外,双击后释放节点的功能将是:
var node = g.selectAll(".nodes")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.style("fill", "black")
// Next two lines -> Pin down functionality
.on('dblclick', releasenode)
.call(node_drag);
var node_drag = d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
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);
// Allows NODE FIXING
// d.fx = null;
// d.fy = null;
}
function releasenode(d) {
d.fx = null;
d.fy = null;
}