Links direction when set fromSpot: go.Spot.NotTopSide and portSpreading: go.Node.SpreadingNone

As suggested earlier We are using following configuration for plotting links:

toSpot: go.Spot.NotBottomSide,
fromSpot: go.Spot.NotTopSide,
portSpreading: go.Node.SpreadingNone,

And it is plotting as follows:

Here from the diamond node we were expecting that the link towards node 1 will come from left, but link for node 2 must be from bottom and link towards node 3 must be from right.
But all 3 links are coming from left.

Can you please guide where are we going wrong…?

Maybe your layout is setting the Link.fromSpot and Link.toSpot? What Layout are you using? Consider setting TreeLayout.setsPortSpot, TreeLayout.setsChildPortSpot, or LayeredDigraphLayout.setsPortSpots to false.

Here’s what I just tried:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
function init() {
  var $ = go.GraphObject.make;

  myDiagram =
    $(go.Diagram, "myDiagramDiv",
      {
        layout: $(go.TreeLayout,
          { angle: 90, setsPortSpot: false, setsChildPortSpot: false })
      });

  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      {
        fromSpot: go.Spot.NotTopSide,
        toSpot: go.Spot.NotBottomSide,
        portSpreading: go.Node.SpreadingNone,
        width: 150
      },
      new go.Binding("width"),
      $(go.Shape, { fill: "white" },
        new go.Binding("fill", "color")),
      $(go.TextBlock, { margin: 8 },
        new go.Binding("text"))
    );

  myDiagram.linkTemplate =
    $(go.Link,
      { routing: go.Link.Orthogonal },
      $(go.Shape)
    );

  myDiagram.model = new go.GraphLinksModel(
  [
    { key: 1, text: "Alpha", color: "lightblue", width: 50 },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen" },
    { key: 4, text: "Delta", color: "pink" }
  ],
  [
    { from: 1, to: 2 },
    { from: 1, to: 3 },
    { from: 1, to: 4 }
  ]);
}
  </script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
</body>
</html>

The result is I think exactly what you expect:

We have already set:

setsPortSpot: false, 
setsChildPortSpot: false

Only Difference I see in above diagram is of routing.
Initially We set the routing to go.Link.Orthogonal
But later we startAvoiding method is call to change routing to AvoidNodes.

But we would need AvoidNodes as per our requirement

Whether the routing is Orthogonal or AvoidsNodes doesn’t matter for this situation.

What I gave you works the way that you want, yes? How is it different from your app? (Just in things that matter for this issue, of course.)

Hi, I have created short demo where it is going wrong:

<!DOCTYPE html>
<html>
<head>
  <title>Asynchronous AvoidsNodes Routing</title>
  <!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
  <meta name="description" content="Asynchronously route a few Orthogonal Links to be AvoidsNodes routing, to speed up initial rendering of large diagrams">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/gojs"></script> 
  <script id="code">

  // Support for asychronously routing links or JumpOver or JumpGap curve

  // To set Link.routing = go.Link.AvoidsNodes after "InitialLayoutCompleted":
  //   1: set Link.routing = go.Link.Orthogonal in your link templates
  //   2: create an instance of this class for your diagram:
  //       var diag = ...;
  //       var delay = new DelayLinkRoutingCurve(diag);
  //
  // To also set Link.curve = go.Link.JumpOver (or JumpGap):
  //   1: set Link.curve = go.Link.None in your link templates
  //   2: create an instance of this class for your diagram:
  //       var diag = ...;
  //       var delay = new DelayLinkRoutingCurve(diag, go.Link.JumpOver);
  //
  // To set Link.curve = go.Link.JumpOver or JumpGap without setting routing = go.Link.AvoidsNodes:
  //   1: set Link.curve = go.Link.None and Link.routing = go.Link.Orthogonal in your link templates
  //   2: create an instance of this class for your diagram:
  //       var diag = ...;
  //       var delay = new DelayLinkRoutingCurve(diag, go.Link.JumpOver, go.Link.Orthogonal);

  // If you no longer need a DelayLinkRoutingCurve, set its .diagram = null.
  // This will remove the listeners that it had registered on the Diagram.

  // Two approaches for incrementally routing links with AvoidsNodes routing,
  // assuming links initially have Orthogonal routing:
  // 1: After the model is loaded and the initial layout has happened,
  //    start asynchronously routing a few links at a time until there are none left.
  // 2: When the user scrolls, make sure any links that might be shown
  //    in the viewport are routed first.

  function DelayLinkRoutingCurve(diagram, curve, routing) {
    if (!curve) curve = go.Link.None;
    if (!routing) routing = go.Link.AvoidsNodes;
    this._diagram = null;
    this._routing = routing;
    this._curve = curve;
    this._batch = 10;

    this._AllOrthos = new go.Set();  // all links that need to be routed
    this._ViewOrthos = new go.Set(); // just those links found in or crossing the current viewport
    this._ViewportBounds = new go.Rect();  // last viewport bounds
    this._ilc = this.startAvoiding.bind(this);
    this._vbc = this.updateLinksInViewport.bind(this);
    this._am = this.avoidMore.bind(this);
    this._jm = this.jumpMore.bind(this);

    if (diagram) this.diagram = diagram;
  }

  // default value: null
  Object.defineProperty(DelayLinkRoutingCurve.prototype, "diagram",
    {
      get: function() { return this._diagram; },
      set: function(val) {
        var old = this._diagram;
        if (val !== old) {
          if (old) {
            old.removeDiagramListener("InitialLayoutCompleted", this._ilc);
            old.removeDiagramListener("ViewportBoundsChanged", this._vbc);
            this._AllOrthos.clear();
          }
          this._diagram = val;
          if (val) {
            val.addDiagramListener("InitialLayoutCompleted", this._ilc);
            val.addDiagramListener("ViewportBoundsChanged", this._vbc);
          }
        }
      }
    });

  // default value: go.Link.AvoidsNodes
  Object.defineProperty(DelayLinkRoutingCurve.prototype, "routing",
    {
      get: function() { return this._routing; },
      set: function(val) { this._routing = val; }
    });

  // default value: go.Link.None
  Object.defineProperty(DelayLinkRoutingCurve.prototype, "curve",
    {
      get: function() { return this._curve; },
      set: function(val) { this._curve = val; }
    });

  // default value: 10
  Object.defineProperty(DelayLinkRoutingCurve.prototype, "batch",
    {
      get: function() { return this._batch; },
      set: function(val) { this._batch = val; }
    });

  DelayLinkRoutingCurve.prototype.startAvoiding = function() {
    var delay = this;
    var remaining = 0;
    if (delay.routing !== go.Link.None && delay.routing !== go.Link.Orthogonal) {
      delay._AllOrthos.clear();
      delay.diagram.links.each(function(l) {
        if (l.routing === go.Link.Orthogonal) delay._AllOrthos.add(l);
      });
      delay.updateLinksInViewport();
      remaining = delay._AllOrthos.count;
      // to improve initial responsiveness, don't AvoidsNodes route any links until after a delay
      setTimeout(delay._am, 10);
    } else if (delay.curve !== go.Link.None && delay.curve !== go.Link.Bezier) {
      remaining = 1;
      setTimeout(delay._jm, 10);
    }

    delay.onUpdate(remaining);
  }

  DelayLinkRoutingCurve.prototype.updateLinksInViewport = function() {
    var delay = this;
    // don't search again in viewport if viewport bounds hasn't changed
    if (delay._ViewportBounds.equals(delay.diagram.viewportBounds)) return;
    if (delay.routing !== go.Link.None && delay.routing !== go.Link.Orthogonal) {
      setTimeout(function() {
        delay._ViewportBounds.set(delay.diagram.viewportBounds);
        var links = delay.diagram.findObjectsIn(delay._ViewportBounds,
                      function(x) { var p = x.part; return (p instanceof go.Link) ? p : null; },
                      null,
                      true);
        // make Orthogonal Links in the viewport take routing precedence over Links that are elsewhere
        delay._ViewOrthos.clear();
        links.each(function(l) {
          if (l.routing === go.Link.Orthogonal) delay._ViewOrthos.add(l);
        });
      }, 10);
    }
  }
  
  DelayLinkRoutingCurve.prototype.avoidMore = function() {
    var delay = this;
    if (delay.diagram.currentTool !== delay.diagram.defaultTool) {
      setTimeout(delay._am, 1000);  // process events for tools
    } else {
      // route one or more links, if any need it
      if (delay._AllOrthos.count > 0) {
        delay.diagram.commit(function(diag) {
          for (var i = 0; i < delay._batch; i++) {  // could be smarter and do more in each batch if they are quick enough
            var link = delay._ViewOrthos.first();  // first route links in view
            if (!link) link = delay._AllOrthos.first();  // otherwise pick another link to route
            if (!link) break;  // all done?
            link.routing = delay.routing;
            delay._AllOrthos.remove(link);
            delay._ViewOrthos.remove(link);
          }
        }, null);  // skipsUndoManager
      }

      // if there are any remaining, do them later
      var remaining = delay._AllOrthos.count;
      if (remaining > 0) {
        setTimeout(delay._am, 10);
      } else if (delay.curve !== go.Link.None && delay.curve !== go.Link.Bezier) {
        remaining = 1;
        setTimeout(delay._jm, 10);
      }

      delay.onUpdate(remaining);
    }
  }

  DelayLinkRoutingCurve.prototype.jumpMore = function() {
    var delay = this;
    delay.diagram.commit(function(diag) {
      diag.links.each(function(l) {
        if (l.curve === go.Link.None && l.isOrthogonal) l.curve = delay.curve;
      });
    }, null);  // skipsUndoManager

    delay.onUpdate(0);
  }

  DelayLinkRoutingCurve.prototype.onUpdate = function(numremaining) { }
  // end of DelayLinkRoutingCurve class


  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          layout: $(go.TreeLayout,{
			  layerSpacing: 60, // Spacing between the Layers
			  nodeSpacing: 60, // Spacing between the Columns
			  angle: 90, // value can be  0(left to right)/90(top to bottom)/180(right to left)/270(bottom to top)
			  //alignment: go.TreeLayout.AlignmentStart,
			  // layerStyle: go.TreeLayout.LayerSiblings,
			  // arrangement: go.TreeLayout.ArrangementVertical,
			  // compaction: go.TreeLayout.CompactionBlock,
			  setsChildPortSpot: false,
			  setsPortSpot: false,
			}),
			model: $(go.GraphLinksModel, {
			  linkKeyProperty: 'key', // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
			}),
          "InitialLayoutCompleted": function(e) {
            // scroll to where there are some nodes
            e.diagram.select(e.diagram.nodes.first());
            e.diagram.commandHandler.scrollToPart(e.diagram.nodes.first());
          },
          "animationManager.isEnabled": false
        });

    // using DelayLinkRoutingCurve:
    var delay = new DelayLinkRoutingCurve(myDiagram, go.Link.JumpOver);
    // FOR DEBUGGING in this sample only: just to show how many links still need to have routing AvoidsNodes
    delay.onUpdate = function(numremaining) {
      document.getElementById("myInfo").textContent = this._ViewOrthos.count.toString() + " of " + numremaining;
    };

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",{
		  toSpot: go.Spot.NotBottomSide,
        fromSpot: go.Spot.NotTopSide,
        portSpreading: go.Node.SpreadingNone,
	  },
        $(go.Shape, { fill: "white" },
          new go.Binding("fill")),
        $(go.TextBlock, { margin: new go.Margin(18, 28) },
          new go.Binding("text"))
      );

    myDiagram.linkTemplate =
      $(go.Link,
        { routing: go.Link.Orthogonal, corner: 10 },  // NOTE: Orthogonal, not AvoidsNodes
        {
          mouseEnter: function(e, link) { link.path.stroke = "red"; link.path.strokeWidth = 3; },
          mouseLeave: function(e, link) { link.path.stroke = "black"; link.path.strokeWidth = 1.5; }
        },
        $(go.Shape, { strokeWidth: 1.5 })
      );

    // set up initial model
    test();
  }

  
  function test() {
    generate(1500, 2, 6);
  }

  // create a model that is overall somewhat tree-structured but includes many non-tree-structured links
  function generate(numNodes, minChil, maxChil) {
    var nodeArray = [];
    var linkArray = [];
    for (var i = 0; i < numNodes; i++) {
      nodeArray.push({
        key: i,  // the unique identifier
        text: i.toString(),  // some text to be shown by the node template
        fill: go.Brush.randomColor()  // a color to be shown by the node template
      });
    }

    // Randomize the node data
    for (i = 0; i < nodeArray.length; i++) {
      var swap = Math.floor(Math.random() * nodeArray.length);
      var temp = nodeArray[swap];
      nodeArray[swap] = nodeArray[i];
      nodeArray[i] = temp;
    }

    // Takes the random collection of node data and creates a random tree with them.
    // Respects the minimum and maximum number of links from each node.
    // The minimum can be disregarded if we run out of nodes to link to.
    if (nodeArray.length > 1) {
      // keep the Set of node data that do not yet have a parent
      var available = new go.Set();
      available.addAll(nodeArray);
      for (var i = 0; i < nodeArray.length; i++) {
        var parent = nodeArray[i];
        available.remove(parent);

        // assign some number of node data as children of this parent node data
        var children = Math.floor(Math.random() * (maxChil - minChil + 1)) + minChil;
        for (var j = 0; j < children; j++) {
          var child = available.first();
          if (child === null) break;  // oops, ran out already
          available.remove(child);
          linkArray.push({ from: parent.key, to: child.key });
        }
        if (available.count === 0) break;  // nothing left?
      }

      // add some extra non-tree links
      for (var i = 0; i < numNodes/2; i++) {
        linkArray.push({
          from: nodeArray[Math.floor(Math.random()*numNodes)].key,
          to: nodeArray[Math.floor(Math.random()*numNodes)].key
        });
      }
    }

    myDiagram.model = new go.GraphLinksModel([
     {key: -1, text: "START"}
	,{key: "md_52",text:"Decision"}
	,{key: "1_53", text: "1"}
	,{key: "2_54", text: "2"}
	,{key: "1_55", text: "1"}
	,{key: "2_56", text: "2"}
	,{key: "1_57", text: "1"}
	,{key: "2_58", text: "2"}
	,{key: "1_59", text: "1"}
	,{key: "2_60", text: "2"}
	,{key: "-2_61", text: "END"}
	,{key: "3_62", text: "3"}
	,{key: "4_63", text: "4"}
	,{key: "5_64", text: "5"}
	,{key: "4_65", text: "4"}
	,{key: "1_66", text: "1"}
	,{key: "-2_67", text: "END"}
	,{key: "6_68", text: "6"}
	,{key: "-2_69", text: "END"}
	,{key: "-2_70", text: "END"}
	,{key: "7_71", text: "7"}
	,{key: "md_73", text: "Decision"}
	,{key: "8_74", text: "8"}
	,{key: "7_75", text: "7"}
	,{key: "-2_76", text: "END"}
	,{key: "9_77", text: "9"}
	,{key: "7_78", text: "7"}
	,{key: "9_79", text: "9"}
	,{key: "-2_80", text: "END"}
	,{key: "10_81", text: "10"}
	,{key: "1_82", text: "1"}
	,{key: "10_83", text: "10"}
	,{key: "1_84", text: "1"}
	,{key: "10_85", text: "10"}
	,{key: "-2_86", text: "END"}
	,{key: "11_87", text: "11"}
	,{key: "4_88", text: "4"}
	,{key: "5_89", text: "5"}
	,{key: "12_90", text: "12"}
	,{key: "1_91", text: "1"}
	,{key: "-2_92", text: "END"}
	
  ],
  [
     {from: -1, to: "md_52"}
	,{from: "md_52", to: "1_53"}
	,{from: "1_53", to: "2_54"}
	,{from: "2_54", to: "1_55"}
	,{from: "1_55", to: "2_56"}
	,{from: "2_56", to: "1_57"}
	,{from: "1_57", to: "2_58"}
	,{from: "2_58", to: "1_59"}
	,{from: "1_59", to: "2_60"}
	,{from: "2_60", to: "-2_61"}
	,{from: "md_52", to: "3_62"}
	,{from: "3_62", to: "4_63"}
	,{from: "4_63", to: "5_64"}
	,{from: "5_64", to: "4_65"}
	,{from: "4_65", to: "1_66"}
	,{from: "1_66", to: "-2_67"}
	,{from: "md_52", to: "6_68"}
	,{from: "6_68", to: "-2_69"}
	,{from: "-2_69", to: "-2_70"}
	,{from: "md_52", to: "7_71"}
	,{from: "7_71", to: "md_73"}
	,{from: "md_73", to: "8_74"}
	,{from: "8_74", to: "7_75"}
	,{from: "7_75", to: "-2_76"}
	,{from: "md_73", to: "9_77"}
	,{from: "9_77", to: "7_78"}
	,{from: "7_78", to: "9_79"}
	,{from: "9_79", to: "-2_80"}
	,{from: "md_52", to: "10_81"}
	,{from: "10_81", to: "1_82"}
	,{from: "1_82", to: "10_83"}
	,{from: "10_83", to: "1_84"}
	,{from: "1_84", to: "10_85"}
	,{from: "10_85", to: "-2_86"}
	,{from: "md_52", to: "11_87"}
	,{from: "11_87", to: "4_88"}
	,{from: "4_88", to: "5_89"}
	,{from: "5_89", to: "12_90"}
	,{from: "12_90", to: "1_91"}
	,{from: "1_91", to: "-2_92"}
  ]);
  }
  </script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:900px"></div>
  <button onclick="test()">Generate new model</button>
  <span id="myInfo"></span>
</body>
</html>

Have highlighted where links are not properly plotted:

All the links must have came from top right…?

Those link routes meet your requirements, so what is the problem?

Maybe you should not be setting TreeLayout.setsChildPortSpot.