如何在d3版本4中的力模拟中拖动当前节点时禁用动画
以下是用于拖动节点的代码
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '<a href="/test1" rel="nofollow">Test 1</a> | <a href="/test2">Test 2</a>'
@app.route('/test1')
def test1():
return '<a href="/" rel="nofollow">Main Page</a>'
@app.route('/test2')
def test2():
return '<a href="/">Main Page</a>'
if __name__ == '__main__':
app.run(debug=True)
当我试图在拖动方法中停止力时,它不起作用。 请建议我停止动画的最佳方法
请检查此fiddle
答案 0 :(得分:1)
&#34;禁用动画&#34; 并不完全清楚你的意思。我想你正在谈论其他节点的运动......嗯,这是预期的行为,因为你正在重新加热模拟。
一种可能的解决方案是在模拟结束时设置所有节点的fx
和fy
属性:
simulation.on("end", function() {
node.each(function(d) {
d.fx = d.x;
d.fy = d.y;
})
})
这是您更改的代码。等待直到模拟结束(aprox.5秒),然后拖动节点:
var nodes = [{
"id": 1,
"name": "server 1"
}, {
"id": 2,
"name": "server 2"
}, {
"id": 3,
"name": "server 3"
}, {
"id": 4,
"name": "server 4"
}, {
"id": 5,
"name": "server 5"
}, {
"id": 6,
"name": "server 6"
}, {
"id": 7,
"name": "server 7"
}, {
"id": 8,
"name": "server 8"
}, {
"id": 9,
"name": "server 9"
}]
var links = [{
source: 1,
target: 2
}, {
source: 1,
target: 3
}, {
source: 1,
target: 4
}, {
source: 2,
target: 5
}, {
source: 2,
target: 6
}, {
source: 3,
target: 7
}, {
source: 5,
target: 8
}, {
source: 6,
target: 9
}, ]
var index = 10;
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;
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));
update();
function update() {
link = svg.selectAll(".link")
.data(links, function(d) {
return d.target.id;
})
link = link.enter()
.append("line")
.attr("class", "link");
node = svg.selectAll(".node")
.data(nodes, function(d) {
return d.id;
})
node = node.enter()
.append("g")
.attr("class", "node")
.on("click", click)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("circle")
.attr("r", 2.5)
node.append("title")
.text(function(d) {
return d.id;
});
node.append("text")
.attr("dy", 3)
.text(function(d) {
return d.name;
});
simulation
.nodes(nodes)
.on("tick", ticked)
.on("end", function() {
node.each(function(d) {
d.fx = d.x;
d.fy = d.y;
})
})
simulation.force("link")
.links(links);
}
function click(d) {
nodes.push({
id: index,
name: "server " + index
});
links.push({
source: d.id,
target: index
});
index++;
update();
}
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()
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
}
&#13;
.link {
stroke: #aaa;
}
.node {
pointer-events: all;
stroke: none;
stroke-width: 40px;
cursor: pointer;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="400"></svg>
&#13;
答案 1 :(得分:0)
看一下这个例子:http://bl.ocks.org/norrs/2883411因为它似乎可以完成你所追求的目标。
如示例和相关的SO问题(D3 force directed graph with drag and drop support to make selected node position fixed when dropped)中所示,您可能最好创建和使用自己的拖动侦听器来实现此特定行为。
答案 2 :(得分:0)
实际上非常容易。只需不定义:
.call(d3.drag().on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end))
这是控制动画部分的原因,但是由于海量数据或其他原因,您会在图形的后期加载中发现问题,然后我建议添加一个名为.alphaDecay(0.9)的属性,此特殊操作将减少链接长度从而减少了图形的加载时间。