我的图表包含使用D3 [不使用D3力]制作的各种节点/边缘,它们具有节点拖动功能。 我正在尝试实现一种功能,用户可以单击链接上的任何点并拖动到随机点,这样它就会在该边缘创建一个弯曲点到源节点和目标节点之间的拖动点。
我使用svg路径制作的链接与下面的示例Example非常相似,下面给出了使用某些数据的数据制作的弯曲点,我根据原始源节点和目标节点的位置计算代码:
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script>
var width = 400;
var height = 400;
var svg = d3.select('body').append('svg');
svg.attr('width', width);
svg.attr('height', height);
//This is the accessor function we talked about above
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate('linear');
//The data for our line
var lineData = [
{ "x": 1, "y": 5},
{ "x": 60, "y": 30},
{ "x": 100, "y": 60}
];
//The line SVG Path we draw
var lineGraph = svg.append("path")
.attr("d", lineFunction(lineData))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
</script>
&#13;
我需要逻辑方面的帮助,我可以点击链接上的任意一点并拖动&amp;在链接中创建新的弯曲点。
答案 0 :(得分:0)
我为边缘拖动问题Here创建了一个解决方案。虽然欢迎更好的解决方案。
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link {
stroke: #aaa;
}
.node text {
stroke:#333;
cursos:pointer;
}
.node circle{
stroke:#fff;
stroke-width:3px;
fill:#555;
}
</style>
<body>
<p id="first"><p>
<p id="second"><p>
<script>
var data = {
"nodes":[
{"id":"node1","x":100,"y":400},
{"id":"node2","x":500,"y":200},
{"id":"node3","x":600,"y":120},
{"id":"node4","x":900,"y":400}
],
"links":[
{"source":"node2","target":"node1","weight":1,"id":"abc"},
{"source":"node3","target":"node4","weight":3,"id":"xyz"}
]
}
var width = 1200,
height = 500
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("", function(json) {
json = data;
var nodes = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node");
nodes.append("rect")
.attr("width","5").attr("height","5").attr("x",function(d){return d.x}).attr("y",function(d){return d.y});
nodes.append("text")
.attr("dx", 12)
.attr("dy", ".35em").attr("x",function(d){return d.x}).attr("y",function(d){return d.y})
.text(function(d) { return d.id });
var LinkCurve = "linear";
var lineFunction = d3.svg.line()
.x(function(d) {
return d.a;
})
.y(function(d) {
return d.b;
})
.interpolate(LinkCurve);
////////////////////////////////////Edge Drag//////////////////////////////
var EdgeDrag = d3.behavior.drag()
.on("dragstart", dragstartedEdge)
.on("drag", draggedEdge)
.on("dragend", dragEndedEdge);
var firstPointBool = true;
var firstDragX = 0;
var firstDragY = 0;
var bendPointAddPos = 0;
function dragstartedEdge() {
d3.selectAll(".linkInTopology").classed("selectedLink", false).style("stroke", "blue");
d3.select(this).classed("selectedLink", true);
firstPointBool = true;
firstDragX = 0;
firstDragY = 0;
bendPointAddPos = 0;
}
var controlPointsArrLinkDrag = [];
var dragEdgeBool = false;
function draggedEdge(d) {
dragEdgeBool = true;
d3.selectAll(".selectedLink").attr("d", function(l) {
if (firstPointBool) {
firstDragX = d3.event.x;
firstDragY = d3.event.y;
for (i = 0; i < l.controlPoints.length; i += 2) {
var firstAngle = Math.abs((l.controlPoints[i + 1] - firstDragY) / (l.controlPoints[i] - firstDragX));
var secondAngle = Math.abs((firstDragY - l.controlPoints[i + 3]) / (firstDragX - l.controlPoints[i + 2]));
if (firstAngle.toFixed(1) == secondAngle.toFixed(1) && Math.max(l.controlPoints[i], l.controlPoints[i + 2]) >= firstDragX && Math.min(l.controlPoints[i], l.controlPoints[i + 2]) <= firstDragX) {
bendPointAddPos = i + 2;
d3.selectAll(".selectedLink").style("stroke", "red");
}
}
}
var sourceNode = json.nodes.filter(function(d, i) {
return d.id == l.source
})[0];
var targetNode = json.nodes.filter(function(d, i) {
return d.id == l.target
})[0];
// Fetch the initial edge bend points in controlPointsArrLinkDrag array
lineData.length = 0;
controlPointsArrLinkDrag.length = 0;
l.controlPoints.forEach(function(d) {
controlPointsArrLinkDrag.push(d);
})
if (bendPointAddPos != 0) {
controlPointsArrLinkDrag.splice(bendPointAddPos, 0, d3.event.x);
controlPointsArrLinkDrag.splice(bendPointAddPos + 1, 0, d3.event.y);
}
for (i = 0; i < controlPointsArrLinkDrag.length; i += 2) {
lineData.push({
"a": controlPointsArrLinkDrag[i],
"b": controlPointsArrLinkDrag[i + 1]
});
}
///////
return lineFunction(lineData)
})
firstPointBool = false;
}
function dragEndedEdge() {
if (dragEdgeBool) {
d3.selectAll(".selectedLink").attr("d", function(l) {
lineData.length = 0;
for (i = 0; i < controlPointsArrLinkDrag.length; i += 2) {
lineData.push({
"a": controlPointsArrLinkDrag[i],
"b": controlPointsArrLinkDrag[i + 1]
});
}
l.controlPoints.length = 0;
l.controlPoints = controlPointsArrLinkDrag.slice();
return lineFunction(lineData)
})
}
json.links.forEach(function(d,i){
if(i == 0){
d3.select("#first").text("bend-points of link between node1-node2: [" + d.controlPoints + "]")
}
else{
d3.select("#second").text("bend-points of link between node3-node4: [" + d.controlPoints + "]")
}
})
}
////////////////////////////////////////////////////////////////////////////
//The data for our line
var lineData = [];
function setupPolyLinks() {
d3.selectAll(".linkInTopology").remove();
edges = svg.selectAll("linkInTopology")
.data(json.links)
.enter()
.insert("path", ".node")
.attr("class", "linkInTopology").attr("id", function(l) {
return l.id;
}).attr("source", function(l) {
return l.source;
}).attr("target", function(l) {
return l.target;
}).attr("d", function(l) {
lineData.length = 0;
controlPointsArr = [];
var sourceNode = json.nodes.filter(function(d, i) {
return d.id == l.source
})[0];
var targetNode = json.nodes.filter(function(d, i) {
return d.id == l.target
})[0];
lineData.push({
"a": sourceNode.x ,
"b": sourceNode.y
});
controlPointsArr.push(sourceNode.x);
controlPointsArr.push(sourceNode.y);
lineData.push({
"a": targetNode.x ,
"b": targetNode.y
});
controlPointsArr.push(targetNode.x);
controlPointsArr.push(targetNode.y);
l.controlPoints = [];
for (i = 0; i < controlPointsArr.length; i++) {
l.controlPoints.push(controlPointsArr[i]);
}
return lineFunction(lineData)
}).style("stroke-width", "5").attr("stroke", "blue").attr("fill", "none").call(EdgeDrag);
}
setupPolyLinks();
json.links.forEach(function(d,i){
if(i == 0){
d3.select("#first").text("bend-points of link between node1-node2: [" + d.controlPoints + "]")
}
else{
d3.select("#second").text("bend-points of link between node3-node4: [" + d.controlPoints + "]")
}
})
})
</script>
&#13;