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

如何实现支持任意层级任意顺序的d3 SunBurst图动态数据生成

动态生成d3 SunBurst层级数据方案

核心改造逻辑

原有代码硬编码了4层嵌套的匹配逻辑,要支持任意层级、任意顺序排列,核心优化点如下:

  • 把层级顺序作为可配置参数传入,参数顺序就是最终的层级展示顺序
  • 用逐层遍历的方式替代固定嵌套的forEach逻辑,自动适配层级数量
  • 自动识别最末层级,生成不带children、仅携带必填的name和count字段的节点

完整改造代码

// 生成非末层级节点(带children字段,用于挂载下一层数据)
function createNonLeafNode(name) {
  return {
    name: name,
    children: []
  }
}

// 生成末层级节点(不带children字段,携带必填count)
function createLeafNode(name, count) {
  return {
    name: name,
    count: count
  }
}

/**
 * 动态生成SunBurst要求的树形结构
 * @param {string} rootName 根节点显示名称
 * @param {Array} levelDatasets 按层级顺序排列的数据集数组,顺序即层级从高到低的顺序
 * @param {Array} matchFieldMap 匹配字段映射,第n项对应第n+1层数据集需要匹配的父字段列表
 * @returns {Object} 符合d3渲染要求的树形数据
 */
function createDynamicPayload(rootName, levelDatasets, matchFieldMap) {
  const root = {
    name: rootName,
    children: []
  }
  // 无层级数据直接返回根节点
  if (!levelDatasets || levelDatasets.length === 0) return root

  // 初始化第一层节点
  root.children = levelDatasets[0].map(item => createNonLeafNode(item.name))
  // 仅一层数据直接返回
  if (levelDatasets.length === 1) return root

  // 逐层处理后续层级
  for (let levelIdx = 1; levelIdx < levelDatasets.length; levelIdx++) {
    const currentDataset = levelDatasets[levelIdx]
    const isLastLevel = levelIdx === levelDatasets.length - 1

    // 递归遍历上一层所有节点,匹配子数据
    const traverseParentNodes = (nodes, currentDepth, parentNamePath = []) => {
      // 未到目标父层级,继续往下遍历
      if (currentDepth !== levelIdx - 1) {
        nodes.forEach(node => {
          traverseParentNodes(node.children, currentDepth + 1, [...parentNamePath, node.name])
        })
        return
      }

      // 给当前父层级的每个节点匹配子数据
      nodes.forEach(parentNode => {
        const fullParentPath = [...parentNamePath, parentNode.name]
        // 筛选属于当前父节点的子数据
        const matchedChildren = currentDataset.filter(dataItem => {
          return matchFieldMap[levelIdx - 1].every((field, idx) => {
            return dataItem[field] === fullParentPath[idx]
          })
        }).map(dataItem => {
          return isLastLevel 
            ? createLeafNode(dataItem.name, dataItem.count)
            : createNonLeafNode(dataItem.name)
        })
        parentNode.children = matchedChildren
      })
    }

    traverseParentNodes(root.children, 0, [])
  }
  return root
}

使用示例

原固定4层级的调用方式

// 层级顺序:项目类型 > 子项目 > 状态 > 负责人
const levelDatasets = [projectType, subProject, status, assignedTo]
// 匹配字段映射:对应每一层数据集需要匹配的父字段
const matchFieldMap = [
  ['projecttype'], // 子项目层匹配父级(项目类型)的projecttype字段
  ['projecttype', 'subproject'], // 状态层匹配父级的projecttype、subproject字段
  ['projecttype', 'subproject', 'status'] // 负责人层匹配前三层的对应字段
]
// 生成最终数据
const payload = createDynamicPayload('My Project', levelDatasets, matchFieldMap)

调整层级顺序的调用示例

如果要把状态调整到第二层,仅需要修改两个配置项即可,不需要修改核心逻辑:

// 调整层级顺序:项目类型 > 状态 > 子项目 > 负责人
const levelDatasets = [projectType, status, subProject, assignedTo]
// 对应修改匹配字段映射
const matchFieldMap = [
  ['projecttype'], // 状态层匹配项目类型的projecttype字段
  ['projecttype', 'status'], // 子项目层匹配projecttype、status字段
  ['projecttype', 'status', 'subproject'] // 负责人层匹配前三层对应字段
]
const payload = createDynamicPayload('My Project', levelDatasets, matchFieldMap)

注意事项

  • 最末层级的数据集每个项必须携带name和count字段,符合要求
  • 层级数量无限制,最少1层,最多可自定义任意数量
  • 生成的结构完全符合d3 SunBurst的渲染要求,无需额外转换

内容的提问来源于stack exchange,提问作者Srinivas Naik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:24:03