Calculate node in tree layout based on number of child nodes

Hi,
I want to create a tree layout for levels and sublevels as follow –

For example – As level 3 has 2 child nodes, the width of level 3 should be such that it accommodates both child nodes (sublevel3_1& sublevel3_2)
Linking for all nodes must be straight lines.

I was able to achieve this - using tree layout
image

By setting fromSpot: "None", toSpot: "Top" I was able to get the arrow head to point to the center of the child node, but its not a straight line.

  1. How to I create straight line joining from the parent node to the center of the child node?
  2. Calculate the width of parent node based on the width of the child nodes
    Hope this helps -

Thanks

Have you seen Bind Parent Node Width to Width of All Child Nodes ?

Hi, Thanks for your reply. Using CoveringTreeLayout I am able to achieve the following -
image

But I am still not able to render straight arrows connecting to the center of the child nodes. I tried { routing: go.Link.Orthogonal but that too is rendering slanted/bent lines for the arrows
image

Besides recalculating the parent node width based on number of child nodes, the link joining the parent nodes have shortened.
I found nodeSpacing and layerSpacing, but they are changing spacing between the child nodes (ex. Level3_1, Level3_2 in this case) But I want to increase the link length for the parent nodes (ex. between Level2 and Level3)
Can you suggest properties that could fix the two issues I mentioned?
Here’s my code for reference -

<html>
  <head>
    <script src="https://unpkg.com/gojs/release/go-debug.js"></script>
  </head>
  <body>
    <div
      id="myDiagramDiv"
      style="
        border: 1px solid black;
        width: 100%;
        height: 400px;
        position: relative;
        -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
      "
    >
      
    </div>
    <script>
            const $ = go.GraphObject.make;
      
      function CoveringTreeLayout() {
    go.TreeLayout.call(this);
    this.compaction = go.TreeLayout.CompactionNone;  // necessary to avoid potential overlapping nodes
    this.alignment = go.TreeLayout.AlignmentStart;
    this.alternateAlignment = go.TreeLayout.AlignmentStart;
  }
  go.Diagram.inherit(CoveringTreeLayout, go.TreeLayout);

  CoveringTreeLayout.prototype.assignTreeVertexValues = function(v) {
    if (v.childrenCount > 0) {
      if (this.angle === 0 || this.angle === 180) {
        v.height = 0;
      } else {
        v.width = 0;
      }
    }
  };

  CoveringTreeLayout.prototype.commitNodes = function() {
    var vit = this.network.vertexes.iterator;
    while (vit.next()) {
      var v = vit.value;
      var n = v.node;
      if (n === null) continue;
      n.position = new go.Point(v.x, v.y);
      if (v.childrenCount > 0) {
        if (this.angle === 0 || this.angle === 180) {
          n.height = v.subtreeSize.height;
        } else {
          n.width = v.subtreeSize.width;
        }
      }
    }
  };

      var myDiagram = new go.Diagram("myDiagramDiv", {
            layout: $(CoveringTreeLayout, {
                angle: 90,
                setsPortSpot: false,
                setsChildPortSpot: true,
                arrangement: go.TreeLayout.ArrangementHorizontal
            }),
            "undoManager.isEnabled": true
        });

        myDiagram.nodeTemplate = $(
            go.Node,
            "Auto",
            $(
                go.Shape,
                { fill: "white", strokeWidth: 2 },
                new go.Binding("fill", "bgcolor"),
                new go.Binding("figure", "fig")
            ),
            $(
                go.TextBlock,
                { margin: 8, editable: true },
                new go.Binding("text").makeTwoWay()
            )
        );

        myDiagram.linkTemplate = $(
            go.Link,

            {
                fromSpot: go.Spot.BottomSide,
                toSpot: go.Spot.TopSide
            },
            { routing: go.Link.Orthogonal },
            $(go.Shape),
            $(go.Shape, { toArrow: "Standard" })
        );

        myDiagram.linkTemplateMap.add(
            "Test",
            $(
                go.Link,
                { isLayoutPositioned: false, isTreeLink: false },
                $(go.Shape),
                $(go.Shape, { toArrow: "OpenTriangle" })
            )
        );

        myDiagram.model = new go.GraphLinksModel(
            [
                { key: 0, text: "Level1", fig: "RoundedRectangle" },
                {
                    key: 1,
                    text: "Level2",
                    color: "lightblue",
                    border: "blue",
                    fig: "RoundedRectangle"
                },
                { key: 2, text: "Level2_1", bgcolor: "orange", fig: "RoundedRectangle" },
                { key: 3, text: "Level2_2", bgcolor: "lightgreen", fig: "RoundedRectangle"  },
                { key: 4, text: "Level2_3", bgcolor: "pink", fig: "RoundedRectangle"  },
                { key: 11, text: "Level3", bgcolor: "lightblue", fig: "RoundedRectangle"  },
                { key: 12, text: "Level3_1", bgcolor: "orange", fig: "RoundedRectangle"  },
                { key: 13, text: "Level3_2", bgcolor: "lightgreen", fig: "RoundedRectangle"  },
                { key: 50, text: "Level4", fig: "RoundedRectangle"  }
            ],
            [
                { from: 0, to: 1, category: "Test" },
                { from: 1, to: 2 },
                { from: 1, to: 3 },
                { from: 3, to: 4 },
                { from: 1, to: 11, category: "Test" },
                { from: 11, to: 12 },
                { from: 11, to: 13 },
                { from: 11, to: 50, category: "Test" }
            ]
        );

    </script>
  </body>
</html>


Thanks

Are you using the BarLink class that I gave you before?

By the way, you might want to set TreeLayout.arrangementSpacing so as to spread the trees apart a bit more.