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

将带连字符层级文本转为D3.js的flare数据,生成树状图不符预期

修复D3.js树状图层级解析问题

问题概述

输入层级文本后,生成的树状图层级混乱,二级节点b_2、叶子节点d_1/d_2的归属错误,不符合预期的层级结构。

输入文本数据

var inputText = `
- a
  - - b_1
  - - - c_1
  - - - c_2
- b
  - - b_2
  - - - d_1
  - - - d_2
`;

问题原因

原解析函数的层级判断逻辑存在两处核心错误:

  1. 使用lastIndexOf('-') / 2 > depth计算层级,该公式完全不符合输入文本的层级规则,导致子节点归属判断错误。
  2. 循环处理节点时错误地执行index +=1,可能跳过同级节点行,破坏层级结构。

解决方案

1. 修正文本解析函数

替换原parseHierarchicalText函数,通过统计每行的-数量确定层级,使用栈结构维护当前节点路径,确保子节点正确归属到父节点:

function parseHierarchicalText(text) {
    var lines = text.split('\n').filter(line => line.trim() !== ''); // 过滤空行

    // 预处理每行,提取深度和节点名称
    var lineData = lines.map(line => {
        var trimmed = line.trim();
        var dashCount = (trimmed.match(/-/g) || []).length;
        var depth = dashCount - 1; // 1个-对应层级0,2个对应层级1,以此类推
        var name = trimmed.replace(/-/g, '').trim();
        return { depth, name };
    });

    var root = { name: 'Root', children: [] };
    var stack = [{ node: root, depth: -1 }]; // 栈保存当前路径的节点及其层级

    lineData.forEach(current => {
        // 找到当前节点的父节点:弹出栈中层级不小于当前层级的节点
        while (stack[stack.length - 1].depth >= current.depth) {
            stack.pop();
        }
        var parentNode = stack[stack.length - 1].node;
        var newNode = { name: current.name, children: [] };
        parentNode.children.push(newNode);
        stack.push({ node: newNode, depth: current.depth });
    });

    return root;
}

2. 优化绘图样式(可选)

添加连接线样式,确保线条可见:

.link {
    fill: none;
    stroke: #ccc;
    stroke-width: 2px;
}

完整修正后的代码

function parseHierarchicalText(text) {
    var lines = text.split('\n').filter(line => line.trim() !== '');

    var lineData = lines.map(line => {
        var trimmed = line.trim();
        var dashCount = (trimmed.match(/-/g) || []).length;
        var depth = dashCount - 1;
        var name = trimmed.replace(/-/g, '').trim();
        return { depth, name };
    });

    var root = { name: 'Root', children: [] };
    var stack = [{ node: root, depth: -1 }];

    lineData.forEach(current => {
        while (stack[stack.length - 1].depth >= current.depth) {
            stack.pop();
        }
        var parentNode = stack[stack.length - 1].node;
        var newNode = { name: current.name, children: [] };
        parentNode.children.push(newNode);
        stack.push({ node: newNode, depth: current.depth });
    });

    return root;
}

var inputText = `
- a
  - - b_1
  - - - c_1
  - - - c_2
- b
  - - b_2
  - - - d_1
  - - - d_2
`;

var data = parseHierarchicalText(inputText);

// 设置图表尺寸和边距
var margin = {
        top: 20,
        right: 90,
        bottom: 30,
        left: 90
    },
    width = 800 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

// 添加SVG容器
var svg = d3.select("#dendrogram")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// 创建层级布局
var hierarchy = d3.hierarchy(data, d => d.children);
var cluster = d3.cluster().size([height, width - 100]);
var root = cluster(hierarchy);

// 绘制连接线
svg.selectAll('path')
    .data(root.links())
    .enter()
    .append('path')
    .attr('class', 'link')
    .attr('d', d3.linkHorizontal()
        .x(d => d.y)
        .y(d => d.x)
    );

// 绘制节点
var nodes = svg.selectAll('g.node')
    .data(root.descendants())
    .enter()
    .append('g')
    .attr('class', d => 'node' + (d.children ? ' node--internal' : ' node--leaf'))
    .attr('transform', d => 'translate(' + d.y + ',' + d.x + ')');

nodes.append('circle').attr('r', 7);

nodes.append('text')
    .attr('dy', '.35em')
    .attr('x', d => d.children ? -13 : 13)
    .style('text-anchor', d => d.children ? 'end' : 'start')
    .text(d => d.data.name);

效果说明

修正后,树状图将正确呈现预期层级:

  • Root节点下包含a、b两个一级节点
  • a节点的子节点为b_1,b_1的子节点为c_1、c_2
  • b节点的子节点为b_2,b_2的子节点为d_1、d_2

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 08:30:56