最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to ensure the nodes are connected in this tree diagram - Stack Overflow

programmeradmin1浏览0评论

I have the following data structure (the minimum data is provided here, without this it's hard to see the issue as there are a few different ways the data can be nested and the issue can appear fixed with a smaller example):

const data = {
    label: "root",
    children: [
      {
        label: "child_1_A",
      },
      {
        label: "child_1_B",
      },
      {
        label: "child_1_C",
      },
      {
        label: "child_1_D",
      },
      {
        label: "child_1_E",
      },
      {
        label: "child_1_F",
        children: [
          {
            label: "child_2_A",
            children: [
              { label: "child_3_A" },
              { label: "child_3_B" },
              { label: "child_3_C" },
              {
                label: "child_3_D",
              },
            ],
          },
        ],
      },
    ],
  };

I need to render a nested tree diagram with lines which connect all levels.

This works fine for most levels but when I get to a node which has inner nested children the outer line that connects the nodes doesn't join up.

child_4_A has a number of children and the line that should connect all of those children doesn't extend far enough down to child_5_E. The log in the code shows that the line from child_4_A is 190px tall (5 * the 38px for each node) when it should be more 608px tall (which is 16 * 38px). I've tried lots of different things. The code I have to calculate how tall to draw that line is:

  const calculateTotalHeight = (nodes, depth = 0) => {
    if (!nodes || nodes.length === 0) return 0;

    const nodeHeight = 38;
    let totalHeight = 0;

    // Process all siblings
    for (let i = 0; i < nodes.length - 1; i++) {
      // Add height for this sibling
      totalHeight += nodeHeight;

      // Process children for all nodes, not just non-last siblings
      if (nodes[i].children && nodes[i].children.length > 0) {
        totalHeight += calculateTotalHeight(nodes[i].children, depth + 1);
      }
    }
     console.log(label, totalHeight, depth);
    return totalHeight;
  };

If I remove the -1 from the for loop then every node with a child ends up with a line being drawn to the bottom of the diagram. The code somehow needs to take all nested children in to account but stop drawing the vertical line at the last child/sibling.

I have the following data structure (the minimum data is provided here, without this it's hard to see the issue as there are a few different ways the data can be nested and the issue can appear fixed with a smaller example):

const data = {
    label: "root",
    children: [
      {
        label: "child_1_A",
      },
      {
        label: "child_1_B",
      },
      {
        label: "child_1_C",
      },
      {
        label: "child_1_D",
      },
      {
        label: "child_1_E",
      },
      {
        label: "child_1_F",
        children: [
          {
            label: "child_2_A",
            children: [
              { label: "child_3_A" },
              { label: "child_3_B" },
              { label: "child_3_C" },
              {
                label: "child_3_D",
              },
            ],
          },
        ],
      },
    ],
  };

I need to render a nested tree diagram with lines which connect all levels.

This works fine for most levels but when I get to a node which has inner nested children the outer line that connects the nodes doesn't join up.

child_4_A has a number of children and the line that should connect all of those children doesn't extend far enough down to child_5_E. The log in the code shows that the line from child_4_A is 190px tall (5 * the 38px for each node) when it should be more 608px tall (which is 16 * 38px). I've tried lots of different things. The code I have to calculate how tall to draw that line is:

  const calculateTotalHeight = (nodes, depth = 0) => {
    if (!nodes || nodes.length === 0) return 0;

    const nodeHeight = 38;
    let totalHeight = 0;

    // Process all siblings
    for (let i = 0; i < nodes.length - 1; i++) {
      // Add height for this sibling
      totalHeight += nodeHeight;

      // Process children for all nodes, not just non-last siblings
      if (nodes[i].children && nodes[i].children.length > 0) {
        totalHeight += calculateTotalHeight(nodes[i].children, depth + 1);
      }
    }
     console.log(label, totalHeight, depth);
    return totalHeight;
  };

If I remove the -1 from the for loop then every node with a child ends up with a line being drawn to the bottom of the diagram. The code somehow needs to take all nested children in to account but stop drawing the vertical line at the last child/sibling.

Share edited Feb 11 at 8:55 Mike Rifgin asked Feb 10 at 12:51 Mike RifginMike Rifgin 10.8k22 gold badges77 silver badges115 bronze badges 8
  • 1 How to debug small programs StackOverflow is a question-and-answer site for specific questions about actual code; “I wrote some buggy code that I can’t fix” is not a question, it’s a story, and not even an interesting story. – jabaa Commented Feb 10 at 13:44
  • it's not buggy code at all and it contains a specific question about actual code. It's not a story. – Mike Rifgin Commented Feb 10 at 14:34
  • The question contains a code dump and the question how to fix this code. There aren't any debugging details. The problem isn't isolated. There is no minimal reproducible example. The specific problem isn't analyzed and described. I assume you've already used the debugger. What is the first line that produces unexpected behavior? What's the actual behavior and what is the expected behavior? Where do you add the height of the child nodes? – jabaa Commented Feb 10 at 14:37
  • The entire code is for illustration only, in case someone wants to run the whole example, I provided the details of the specific problem and have analyzed the issue. Your analysis of this is incorrect and unfair and has been flagged as such. I can add debugging details. – Mike Rifgin Commented Feb 10 at 14:40
  • Let's again assume, you've already used the debugger. Which exact line calculates the wrong height? What is the input, what is the expected height and what is the actual height? Why do we need more than 4 or 5 nodes for a minimal reproducible example? – jabaa Commented Feb 10 at 14:43
 |  Show 3 more comments

1 Answer 1

Reset to default -1

What I'm getting from this is that you need to draw a line from a parent node down to the last child of that node. How can you determine how long the line should be?

Notice that the nodes are ordered vertically according to a preorder traversal. Therefore, assuming that you know how much vertical space a node takes up, this is just a matter of calculating the distance between a parent and its last child in a preorder traversal. Given your tree, the following code does exactly that:

const data = {
    label: "root",
    children: [
      {
        label: "child_1_A",
      },
      {
        label: "child_1_B",
      },
      {
        label: "child_1_C",
      },
      {
        label: "child_1_D",
      },
      {
        label: "child_1_E",
      },
      {
        label: "child_1_F",
        children: [
          {
            label: "child_2_A",
            children: [
              { label: "child_3_A" },
              { label: "child_3_B" },
              { label: "child_3_C" },
              {
                label: "child_3_D",
                children: [
                  {
                    label: "child_4_A",
                    children: [
                      {
                        label: "child_5_A",
                        children: [
                          {
                            label: "child_6_A",
                          },
                        ],
                      },
                      {
                        label: "child_5_B",
                        children: [
                          {
                            label: "child_6_B",
                          },
                        ],
                      },
                      {
                        label: "child_5_C",
                      },
                      {
                        label: "child_5_D",
                        children: [
                          {
                            label: "child_6_C",
                            children: [
                              {
                                label: "child_7_A",
                                children: [
                                  {
                                    label: "child_8_A",
                                  },
                                  {
                                    label: "child_8_B",
                                    children: [
                                      {
                                        label: "child_9_A",
                                        children: [
                                          {
                                            label: "child_10_A",
                                            children: [
                                              {
                                                label: "child_11_A",
                                              },
                                              {
                                                label: "child_11_B",
                                                children: [
                                                  {
                                                    label: "child_12_A",
                                                  },
                                                ],
                                              },
                                            ],
                                          },
                                        ],
                                      },
                                    ],
                                  },
                                ],
                              },
                            ],
                          },
                          {
                            label: "child_6_D",
                          },
                        ],
                      },
                      {
                        label: "child_5_E",
                        children: [
                          {
                            label: "child_6_E",
                            children: [
                              {
                                label: "child_7_B",
                              },
                              {
                                label: "child_7_C",
                                children: [
                                  {
                                    label: "child_8_C",
                                  },
                                ],
                              },
                            ],
                          },
                        ],
                      },
                    ],
                  },
                ],
              },
            ],
          },
        ],
      },
    ],
  };

let counter = 0;

function preorderDistance(root, parentIndex = null) {
    if (parentIndex !== null) {
        root.distanceFromParent = counter - parentIndex;
    }
    
    // console.log(root);
    // console.log(root.children);
    
    let curIndex = counter++;
    if (root.children) {
        for (let child of root.children) {
            preorderDistance(child, curIndex);
        }
    }
}

preorderDistance(data);

console.log(JSON.stringify(data, null, 2));

The result is as follows:

{
  "label": "root",
  "children": [
    {
      "label": "child_1_A",
      "distanceFromParent": 1
    },
    {
      "label": "child_1_B",
      "distanceFromParent": 2
    },
    {
      "label": "child_1_C",
      "distanceFromParent": 3
    },
    {
      "label": "child_1_D",
      "distanceFromParent": 4
    },
    {
      "label": "child_1_E",
      "distanceFromParent": 5
    },
    {
      "label": "child_1_F",
      "children": [
        {
          "label": "child_2_A",
          "children": [
            {
              "label": "child_3_A",
              "distanceFromParent": 1
            },
            {
              "label": "child_3_B",
              "distanceFromParent": 2
            },
            {
              "label": "child_3_C",
              "distanceFromParent": 3
            },
            {
              "label": "child_3_D",
              "children": [
                {
                  "label": "child_4_A",
                  "children": [
                    {
                      "label": "child_5_A",
                      "children": [
                        {
                          "label": "child_6_A",
                          "distanceFromParent": 1
                        }
                      ],
                      "distanceFromParent": 1
                    },
                    {
                      "label": "child_5_B",
                      "children": [
                        {
                          "label": "child_6_B",
                          "distanceFromParent": 1
                        }
                      ],
                      "distanceFromParent": 3
                    },
                    {
                      "label": "child_5_C",
                      "distanceFromParent": 5
                    },
                    {
                      "label": "child_5_D",
                      "children": [
                        {
                          "label": "child_6_C",
                          "children": [
                            {
                              "label": "child_7_A",
                              "children": [
                                {
                                  "label": "child_8_A",
                                  "distanceFromParent": 1
                                },
                                {
                                  "label": "child_8_B",
                                  "children": [
                                    {
                                      "label": "child_9_A",
                                      "children": [
                                        {
                                          "label": "child_10_A",
                                          "children": [
                                            {
                                              "label": "child_11_A",
                                              "distanceFromParent": 1
                                            },
                                            {
                                              "label": "child_11_B",
                                              "children": [
                                                {
                                                  "label": "child_12_A",
                                                  "distanceFromParent": 1
                                                }
                                              ],
                                              "distanceFromParent": 2
                                            }
                                          ],
                                          "distanceFromParent": 1
                                        }
                                      ],
                                      "distanceFromParent": 1
                                    }
                                  ],
                                  "distanceFromParent": 2
                                }
                              ],
                              "distanceFromParent": 1
                            }
                          ],
                          "distanceFromParent": 1
                        },
                        {
                          "label": "child_6_D",
                          "distanceFromParent": 10
                                label: "child_7_B",
                        }
                      ],
                      "distanceFromParent": 6
                    },
                    {
                      "label": "child_5_E",
                      "children": [
                        {
                          "label": "child_6_E",
                          "children": [
                            {
                              "label": "child_7_B",
                              "distanceFromParent": 1
                            },
                            {
                              "label": "child_7_C",
                              "children": [
                                {
                                  "label": "child_8_C",
                                  "distanceFromParent": 1
                                }
                              ],
                              "distanceFromParent": 2
                            }
                          ],
                          "distanceFromParent": 1
                        }
                      ],
                      "distanceFromParent": 17
                    }
                  ],
                  "distanceFromParent": 1
                }
              ],
              "distanceFromParent": 4
            }
          ],
          "distanceFromParent": 1
        }
      ],
      "distanceFromParent": 6
    }
  ]
}

Once you have the distance from the parent, you can simply multiply to get your answer.

发布评论

评论列表(0)

  1. 暂无评论