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

如何优雅地将嵌套结构递归映射为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);

代码说明

  1. 递归遍历函数:traverseNode负责处理单个节点,先将节点存入nodes,再遍历子节点生成关联边,然后递归处理子节点
  2. 关联边生成:每处理一个子节点,就创建一条包含id、source(父节点ID)、target(子节点ID)的边,边的ID自动递增
  3. 兼容性处理:用可选链操作符?.判断子节点是否存在,避免空指针错误

注意事项

  • 如果你不需要nodes数组里的id字段,可以直接从nodes.push的对象中移除,但强烈建议保留——D3的力导向图可以直接用节点ID匹配source和target,比用数组索引更可靠(不会因为节点顺序变化导致关联错误)
  • 代码完全基于原生JavaScript,不需要依赖任何第三方库,运行环境友好

内容的提问来源于stack exchange,提问作者Oprisor Valeriu Vladut

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:33:11