You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 00:07:54