如果已经选择了一个节点(firstNode不为null),则将新节点(d)与已选择的节点(firstNode)连接。
将新连线的数据添加到linkData数组中。
重启力模拟以更新图形。
更新连线数据:
使用join方法来更新连线。join方法结合了enter、update和exit三个操作,使得您可以同时处理新添加的元素、更新现有元素和移除不再需要的元素。
箭头标记:
attr(“marker-end”, “url(#arrow)”)将箭头标记应用到每个连线的末端。
可能的改进
确保箭头标记已定义:
在使用marker-end之前,确保您已经在SVG中定义了箭头标记。
javascript
const defs = svg.append(“defs”);
defs.append(“marker”)
.attr(“id”, “arrow”)
.attr(“markerUnits”, “strokeWidth”)
.attr(“markerWidth”, 6)
.attr(“markerHeight”, 6)
.attr(“viewBox”, “0 -3 6 6”)
.append(“path”)
.attr(“d”, “M0,-3L6,0L0,3”)
.attr(“fill”, “#999”);
确保link选择集已初始化:
在您的代码中,link选择集应该在添加连线之前初始化。
javascript
var link = svg.append(“g”)
.attr(“class”, “links”)
.selectAll(“line”);
在tick事件中更新连线位置:
确保在力模拟的tick事件中更新连线的位置。
javascript
simulation.on(“tick”, function() {
link
.attr(“x1”, d => d.source.x)
.attr(“y1”, d => d.source.y)
.attr(“x2”, d => d.target.x)
.attr(“y2”, d => d.target.y);
});
处理连线数据的id属性:
确保您的节点数据中包含id属性,并且在添加连线时使用这些id。
完整的代码示例
结合上述改进,以下是完整的代码示例:
javascript
// 初始化SVG和力模拟
var svg = d3.select(“body”).append(“svg”)
.attr(“width”, 600)
.attr(“height”, 400);
var simulation = d3.forceSimulation(nodes)
.force(“link”, d3.forceLink().id(function(d) { return d.id; }))
.force(“charge”, d3.forceManyBody())
.force(“center”, d3.forceCenter(300, 200));
// 定义箭头标记
var defs = svg.append(“defs”);
defs.append(“marker”)
.attr(“id”, “arrow”)
.attr(“markerUnits”, “strokeWidth”)
.attr(“markerWidth”, 6)
.attr(“markerHeight”, 6)
.attr(“viewBox”, “0 -3 6 6”)
.append(“path”)
.attr(“d”, “M0,-3L6,0L0,3”)
.attr(“fill”, “#999”);
// 初始化连线选择集
var link = svg.append(“g”)
.attr(“class”, “links”)
.selectAll(“line”);
// 更新力模拟的节点和连线位置
simulation.on(“tick”, function() {
link
.attr(“x1”, d => d.source.x)
.attr(“y1”, d => d.source.y)
.attr(“x2”, d => d.target.x)
.attr(“y2”, d => d.target.y);
});
// 节点点击事件,添加连线
var firstNode = null;
node.on(“click”, function(event, d) {
if (firstNode) {
// 添加连线
linkData.push({ source: firstNode.id, target: d.id });
console.log(linkData, “linkdata31113”);
simulation.force(“link”).links(linkData);
simulation.alpha(1).restart(); // 重启力模拟
// 更新连线数据绑定
link = link.data(linkData).join(
enter => enter.append(“line”)
.attr(“stroke”, “#999”)
.attr(“stroke-width”, 2)
.attr(“marker-end”, “url(#arrow)”),
update => update, // 更新现有元素
exit => exit.remove() // 移除多余的元素
);
firstNode = null;
} else {
firstNode = d;
}
});
这段代码确保了在点击两个节点时动态添加连线,并且箭头标记正确配置,使得箭头只显示在连线的末端。
以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!