我创建了一些基本节点和链接,用D3创建一个力导向图。我在拖动函数上设置了一些基本逻辑,以便在拖动节点时返回到其原始起始位置。这很好用,直到我把它们连在一起。如何让链中的所有节点在dragend之后返回其原始位置?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.Properties{
fill: yellow;
stroke: black;
stroke-width: 2px;
}
.link {
stroke: #777;
stroke-width: 2px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
//Most of these variables are just used to calculate original position
var width = 960, height = 500, colors = d3.scale.category10();
var svg = null, force = null;
var circle = null, path = null;
var nodes = null, links = null;
var nodesArray = null, linkArray = null;
var count = 0;
var element = "body"; var numEdges = 4, numNodes = 5;
var i = 0; var L = 16, r = 12, lineLimit = 10;
var d = 2 * r + L;
var R = (count - 1) * d;
var m = width / 2;
var X;
svg = d3.selectAll(element).append('svg').attr('width', width).attr('height', height);
//Load nodes and links original positions
nodes = d3.range(numNodes).map(function () {
X = m - (R / 2) + (i * d);
++i;
return {
x: X,
y: (height) / 3,
fx: X,
fy: height / 3,
id: i-1,
reflexive: true,
r: 12
};
});
for (var i = 0; i < numNodes; ++i) {
d3.select(element).append("h3").text("Node " + i + ": " + nodes[i].id);
}
i = -1;
links = d3.range(numEdges).map(function () {
i++;
return {
//
source: nodes[i],
target: nodes[i+1],
left: false,
right: true
}
});
for (var i = 0; i < numEdges; ++i) {
d3.select(element).append("h3").text("Source: " + links[i].source.id + " Target: " + links[i].target.id);
}
force = d3.layout.force().size([width, height]).nodes(nodes).links(links).linkDistance(40).linkStrength(0.1).charge(-300);
var drag = force.drag()
.on('dragstart', dragstart)
.on('drag', drag)
.on('dragend', dragend);
linkArray = svg.selectAll('.link').data(links).enter().append('line').attr('class', 'link')
.attr('x1', function (d) {
return nodes[d.source.id].x;
})
.attr('y1', function (d) { return nodes[d.source.id].y; })
.attr('x2', function (d) { return nodes[d.target.id].x; })
.attr('y2', function (d) { return nodes[d.target.id].y; });
var circleGroup = svg.selectAll("g").data(nodes);
var groupEnter = circleGroup.enter().append("g").attr("transform", function(d){return "translate("+[d.x,d.y]+")";}).call(drag);
var circle = groupEnter.append("circle").attr("cx", 0).attr("cy", -4).attr("r", function(d){return d.r;}).attr("class", "Properties");
var label = circleGroup.append("text").text(function(d){return d.id;}).attr({"alignment-baseline": "middle", "text-anchor": "middle" }).attr("class", "id");
force.on('tick', tick);
force.start();
var originalPosition = [];
function dragstart(d) {
originalPosition[0] = d.x;
originalPosition[1] = d.y;
console.log("Start: ", originalPosition[0], originalPosition[1]);
}
function drag() {
var m = d3.mouse(this);
d3.select(this)
.attr('cx', m[0])
.attr('cy', m[1]);
}
function dragend(d) {
console.log("End: ", d.x, d.y);
d3.select(this).transition().attr('cx', originalPosition[0]).attr('cy', originalPosition[1]);
}
function tick() {
circleGroup.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
linkArray
.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; });
}
</script>
答案 0 :(得分:2)
我在拖动开始时做了类似的事情,保留原始图形数据的克隆,如下所示:
function dragstart(d) {
clone1 = JSON.parse(JSON.stringify(graph));
}
在拖动结束时,我将存储的克隆x / y / px / py属性复制回图形节点,以便它返回到旧位置,如下所示:
function dragend(d) {
clone1.nodes.forEach(function(n,i){
graph.nodes[i].px=n.px
graph.nodes[i].py=n.py
graph.nodes[i].x=n.x
graph.nodes[i].y=n.y
});
}
工作代码here。