如何优雅地将嵌套结构递归映射为D3.js力导向图所需的Nodes与Links数组
解决方案:嵌套结构转D3力导向图的Nodes与Links数组
我来帮你搞定这个问题!其实不用Lodash也能轻松实现,用原生JavaScript的递归遍历就可以完美解决,逻辑清晰且容易维护。
核心思路
我们需要完成两个核心操作:
- 提取所有节点:递归遍历嵌套结构,把每个对象都拉平到一维的
nodes数组中,不管原嵌套深度 - 生成关联边:每遇到一个父节点的子对象,就创建一条从父节点ID指向子节点ID的
link,同时累计边的ID
完整实现代码
function transformToD3Data(nestedData) { const nodes = []; const links = []; let currentLinkId = 0; // 递归遍历嵌套结构的函数 const traverseNode = (node, parentNodeId) => { // 将当前节点加入nodes数组(建议保留id,方便后续关联边匹配) nodes.push({ id: node.id, name: node.name, linkType: node.linkType }); // 如果当前节点有子节点,生成关联边并递归处理子节点 if (node.children?.length) { node.children.forEach(childNode => { // 添加父节点到子节点的关联边 links.push({ id: currentLinkId++, source: node.id, target: childNode.id }); // 递归处理子节点 traverseNode(childNode, node.id); }); } }; // 遍历顶层的所有节点 nestedData.forEach(rootNode => traverseNode(rootNode)); return { nodes, links }; } // 测试你的输入数据 const inputData = [ { "id": 0, "name":"Name0", "linkType":"PROFESSIONAL", "children":[ { "id": 1, "name":"Name1", "linkType":"FAMILY", "children":[ { "id": 2, "name":"Name2", "linkType":"FAMILY", "children":[ { "id": 3, "name":"Name3", "linkType":"FAMILY" }, { "id": 4, "name":"Name4", "linkType":"FAMILY" } ] }, { "id": 5, "name":"Name5", "linkType":"FAMILY" } ] }, { "id": 6, "name":"Name6", "linkType":"FAMILY" } ] }, { "id": 7, "name":"Name7", "linkType":"PROFESSIONAL", "children":[ { "id": 8, "name":"Name8", "linkType":"FAMILY", "children":[ { "id": 9, "name":"Name9", "linkType":"FAMILY" }, { "id": 10, "name":"Name10", "linkType":"FAMILY" } ] }, { "id": 11, "name":"Name11", "linkType":"FAMILY", "children":[ { "id": 12, "name":"Name12", "linkType":"FAMILY", "children":[ { "id": 13, "name":"Name13", "linkType":"FAMILY" }, { "id": 14, "name":"Name14", "linkType":"FAMILY" } ] }, { "id": 15, "name":"Name15", "linkType":"FAMILY" } ] } ] } ]; // 转换数据 const { nodes, links } = transformToD3Data(inputData); // 输出结果 console.log("生成的Nodes数组:", nodes); console.log("生成的Links数组:", links);
代码说明
- 递归遍历函数:
traverseNode负责处理单个节点,先将节点存入nodes,再遍历子节点生成关联边,然后递归处理子节点 - 关联边生成:每处理一个子节点,就创建一条包含
id、source(父节点ID)、target(子节点ID)的边,边的ID自动递增 - 兼容性处理:用可选链操作符
?.判断子节点是否存在,避免空指针错误
注意事项
- 如果你不需要
nodes数组里的id字段,可以直接从nodes.push的对象中移除,但强烈建议保留——D3的力导向图可以直接用节点ID匹配source和target,比用数组索引更可靠(不会因为节点顺序变化导致关联错误) - 代码完全基于原生JavaScript,不需要依赖任何第三方库,运行环境友好
内容的提问来源于stack exchange,提问作者Oprisor Valeriu Vladut
相关产品推荐
相关产品推荐

