如何在D3.js的dragged函数中获取选中元素索引?代码索引错误导致失效
解决D3.js拖拽节点时获取元素索引并更新链接的问题
你的代码无法正常工作的核心原因是dragged函数中idx被硬编码为0,导致只有第一个节点拖拽时链接才会更新。要获取当前拖拽元素的索引,有两种简单可行的方法:
方法一:绑定数据时给节点添加索引属性
在绑定节点数据的阶段,直接给每个节点对象添加索引属性,后续拖拽时直接调用即可:
修改后的完整代码
JavaScript部分
drag_nodes() function drag_nodes() { var data = { nodes: [{ name: "A", x: 200, y: 150 }, { name: "B", x: 140, y: 300 }, { name: "C", x: 300, y: 300 }, { name: "D", x: 300, y: 180 }], links: [{ source: 0, target: 1 }, { source: 1, target: 2 }, { source: 2, target: 3 }, ] }; var c10 = d3.scaleOrdinal(d3.schemeCategory10); var svg = d3.select("body") .append("svg") .attr("width", 1200) .attr("height", 800); var drag = d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended); function dragstarted(event, d) { d3.select(this).raise().attr("stroke", "black"); } function dragged(event, d) { d.x += event.dx d.y += event.dy d3.select(this).attr("cx", d.x).attr("cy", d.y); links.each(function(e, i) { var idx = d.idx; // 获取当前拖拽节点的索引 if (e.source == idx) { d3.select(this).attr("x1", d.x).attr("y1", d.y); }else if (e.target == idx) { d3.select(this).attr("x2", d.x).attr("y2", d.y); } }); } function dragended(event, d) { d3.select(this).attr("stroke", null); } var links = svg.selectAll("link") .data(data.links) .enter() .append("line") .attr("class", "link") .attr("x1", function(l) { var sourceNode = data.nodes.filter(function(d, i) { return i == l.source })[0]; d3.select(this).attr("y1", sourceNode.y); return sourceNode.x }) .attr("x2", function(l) { var targetNode = data.nodes.filter(function(d, i) { return i == l.target })[0]; d3.select(this).attr("y2", targetNode.y); return targetNode.x }) .attr("fill", "none") .attr("stroke", "black"); var nodes = svg.selectAll("node") .data(data.nodes, function(d, i) { d.idx = i; // 绑定数据时为每个节点添加索引属性 return d.name; }) .enter() .append("circle") .attr("class", "node") .attr("cx", function(d) { return d.x }) .attr("cy", function(d) { return d.y }) .attr("r", 15) .attr("fill", function(d, i) { return c10(i); }) .call(drag); }
HTML部分
<script src="https://d3js.org/d3.v7.min.js"></script>
方法二:拖拽时通过数据数组查找索引
如果不想修改节点数据结构,可以在dragged函数中直接通过数据数组查找当前节点的索引:
function dragged(event, d) { d.x += event.dx d.y += event.dy d3.select(this).attr("cx", d.x).attr("cy", d.y); var idx = data.nodes.indexOf(d); // 查找当前节点在数组中的索引 links.each(function(e, i) { if (e.source == idx) { d3.select(this).attr("x1", d.x).attr("y1", d.y); }else if (e.target == idx) { d3.select(this).attr("x2", d.x).attr("y2", d.y); } }); }
注意事项
- 方法一的可靠性更高,尤其是后续数据可能发生增删时,
indexOf可能无法正确匹配节点; - 两种方法都能解决你当前的问题,根据实际场景选择即可。
内容的提问来源于stack exchange,提问作者lucky1928
相关产品推荐
相关产品推荐

