Tanmay Shah
Tanmay Shah

Reputation: 21

Is there a way to plot gojs diagram such that nodes with children follow horizontal structure and without children follow vertical arrangement?

I want to plot a GoJs diagram which follows AlignmentStart pattern. For Every node in tree which have children should come in horizontal arrangement and for every node without children i.e. leaf nodes, should follow vertical arrangement/pattern. This pattern should be followed for nodes at all layers.

I have tried using different layout options to achieve above behavior. I even tried Custom layouts but am unable to handle all cases as my tree can be dynamic i.e. can have multiple layers. Attached is the sample image that i am trying to achieve.

Expected Result Image

Upvotes: 0

Views: 108

Answers (1)

Walter Northwoods
Walter Northwoods

Reputation: 4146

Here's a custom TreeLayout that I believe does what you want:

class ChildlessFirstTreeLayout extends go.TreeLayout {
  makeNetwork(coll) {
    const net = super.makeNetwork(coll);
    new go.Set(net.vertexes).each(parent => {
      const childless = new go.Set();
      const childparents = new go.Set();
      parent.destinationVertexes.each(child => {
        if (child.destinationEdges.count === 0) {
          childless.add(child);
        } else {
          childparents.add(child);
        }
      });
      // if there are both childless and child-ful children,
      // create dummy vertexes
      if (childless.count > 0 && childparents.count > 0) {
        // the first dummy is for the childless children
        const dummy1 = net.createVertex();
        dummy1.copyInheritedPropertiesFrom(this.alternateDefaults);
        dummy1.width = dummy1.height = 0;
        net.addVertex(dummy1);
        net.linkVertexes(parent, dummy1, null);
        childless.each(child => {
          const parentedge = child.sourceEdges.first();
          if (!parentedge) throw new Error("no edge from parent to child???");
          parent.deleteDestinationEdge(parentedge);
          parentedge.fromVertex = dummy1;
          dummy1.addDestinationEdge(parentedge);
        });
        // the second dummy is for the children that have children
        const dummy2 = net.createVertex();
        dummy2.copyInheritedPropertiesFrom(this.rootDefaults);
        dummy2.width = dummy2.height = 0;
        net.addVertex(dummy2);
        net.linkVertexes(parent, dummy2, null);
        childparents.each(child => {
          const parentedge = child.sourceEdges.first();
          if (!parentedge) throw new Error("no edge from parent to child???");
          parent.deleteDestinationEdge(parentedge);
          parentedge.fromVertex = dummy2;
          dummy2.addDestinationEdge(parentedge);
        });
      }
    });
    return net;
  }

  assignTreeVertexValues(v) {
    // change layout for those vertexes with two dummy children
    if (v.childrenCount != 2) return;
    if (v.destinationVertexes.any(c => c.node !== null)) return;
    v.layerSpacing = 0;
    v.nodeIndentPastParent = 0.5;
  }
}

You could use it in the following manner:

      layout:
        $(ChildlessFirstTreeLayout,
          {
            arrangement: go.TreeLayout.ArrangementHorizontal,
            // properties for most of the tree:
            angle: 90,
            alignment: go.TreeLayout.AlignmentStart,
            layerSpacing: 30,
            nodeSpacing: 30,
            // properties for the "last parents":
            treeStyle: go.TreeLayout.StyleLastParents,
            alternateAngle: 90,
            alternateAlignment: go.TreeLayout.AlignmentBottomRightBus,
            alternateLayerSpacing: 30,
            alternateNodeSpacing: 30,
            alternateRowSpacing: 10,
           }),
       . . .

The result: enter image description here

A complete stand-alone sample is at: https://gojs.net/extras/DualTreeLayout3.html As always, the complete source code is in the page itself.

Upvotes: 0

Related Questions