Need to achieve this diagram using dynamic ports layout

No need to influence the nodes by content inside it

OK, then how should the node size be determined?
Presumably you have some notion of how given the number of ports.
Perhaps also influenced by how many ports are on a side?

The node size is determined by number ports it have. Maximum 10 ports it can have.
It doesn’t mean it should only have these many number of ports on a side.
Ultimately, the diagram should look good and connected well

I took the liberty of putting a label showing the portId at each end of each link:

Without calling mergeLinksAtPorts at the end of each layout:

The result after callling mergeLinksAtPorts:

The complete source code follows. Feel free to adapt the code for your own purposes. I didn’t bother changing the size of nodes based on any criteria, but you can do that if you want.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  new go.Diagram("myDiagramDiv",
    {
      layout: new go.ForceDirectedLayout({ randomNumberGenerator: null, maxIterations: 400 }),
      "LayoutCompleted": mergeLinksAtPorts,
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { width: 120, height: 60, locationSpot: go.Spot.Center },
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.Shape, "RoundedRectangle",
      {
        fill: "white", stroke: "gray", strokeWidth: 3,
        portId: "",
        fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides
      }),
    $(go.TextBlock,
      new go.Binding("text"))
  );

myDiagram.linkTemplate =
  $(go.Link,
    { routing: go.Link.AvoidsNodes, corner: 10 },
    //new go.Binding("routing", "straight", s => s ? go.Link.Normal : go.Link.AvoidsNodes),
    $(go.Shape, { stroke: "orange", strokeWidth: 3 }),
    $(go.TextBlock, { segmentIndex: 0, segmentOffset: new go.Point(-10, 0) },
      new go.Binding("text", "fromPort")),
    $(go.TextBlock, { segmentIndex: -1, segmentOffset: new go.Point(10, 0) },
      new go.Binding("text", "toPort"))
  );

function mergeLinksAtPorts(e) {
  const map = new go.Map();
  e.diagram.nodes.each(n => {
    map.clear();
    n.findLinksConnected().each(l => {
      // can we assume no reflexive links?
      if (l.fromNode === n) {
        const fid = l.data.fromPort;
        let arr = map.get(fid);
        if (!arr) map.set(fid, arr = []);
        arr.push(l);
      } else if (l.toNode === n) {
        const tid = l.data.toPort;
        let arr = map.get(tid);
        if (!arr) map.set(tid, arr = []);
        arr.push(l);
      }
    });
    map.each(kvp => {
      const id = kvp.key;
      const arr = kvp.value;
      if (!arr || arr.length <= 1) return;
      const first = arr[0];
      let spot;
      if (first.fromNode === n) {
        spot = computeSpot(n, first.getPoint(0));
      } else if (first.toNode === n) {
        spot = computeSpot(n, first.getPoint(first.pointsCount-1));
      }
      arr.forEach(link => {
        if (link.fromNode === n) {
          link.fromSpot = spot;
        } else if (link.toNode === n) {
          link.toSpot = spot;
        }
      });
    })
  });
}

function computeSpot(node, pt) {
  const b = node.getDocumentBounds();
  return new go.Spot((pt.x - b.x) / (b.width || 1), (pt.y - b.y) / (b.height || 1));
}

const nda = [
  {key: "system1", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system2", portArray : [{portId : 0}, {portId : 1}, {portId : 2}]},
  {key: "system3", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system4", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}]},
  {key: "system5", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system6", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}, {portId : 4}]},
  {key: "system7", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system8", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system9", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}]},
  {key: "system10", portArray : [{portId : 0}, {portId : 1}]}
];
const lda = [
  {"from":"system2","fromPort":0,"to":"system8","toPort":0},
  {"from":"system2","fromPort":2,"to":"system9","toPort":2},
  {"from":"system3","fromPort":0,"to":"system9","toPort":1},
  {"from":"system3","fromPort":1,"to":"system6","toPort":1},
  {"from":"system4","fromPort":2,"to":"system6","toPort":0},
  {"from":"system5","fromPort":0,"to":"system10","toPort":1},
  {"from":"system5","fromPort":1,"to":"system9","toPort":3},
  {"from":"system6","fromPort":0,"to":"system4","toPort":0},
  {"from":"system6","fromPort":2,"to":"system1","toPort":0},
  {"from":"system6","fromPort":3,"to":"system10","toPort":1},
  {"from":"system6","fromPort":4,"to":"system4","toPort":0},
  {"from":"system7","fromPort":0,"to":"system2","toPort":1},
  {"from":"system7","fromPort":1,"to":"system4","toPort":1},
  {"from":"system8","fromPort":0,"to":"system1","toPort":1},
  {"from":"system9","fromPort":0,"to":"system8","toPort":0},
  {"from":"system9","fromPort":2,"to":"system1","toPort":0},
  {"from":"system10","fromPort":1,"to":"system9","toPort":2}
];
myDiagram.model = new go.GraphLinksModel(nda, lda);
  </script>
</body>
</html>

@walter While dragging the nodes, the ports are colliding each other. Is there way to align it automatically without colliding on top of each other?
Initial View


After dragging the nodes

@walter Here you are having ports on the link.
But what if the node should show just port without any links or there are ports that is not connected to any nodes (Node requirement) ?

You keep adding new requirements. From your original description it wouldn’t make sense to have particular positions for ports unless there was at least one connected link determining its position based on the relative location of the node that the link connects with.

Apology for that @walter . I thought there would be requirement for that. No needed. Thanks for the quick response.
BTW,
While dragging the nodes, the ports are colliding each other. Is there way to align it automatically without colliding on top of each other?

Here’s one way to allow interactive dragging of nodes.

If you wanted to show the final configuration during the drag, that’s possible too but would be slower because the natural link routing and the merging step would need to be done on each mouse move.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  new go.Diagram("myDiagramDiv",
    {
      layout: new go.ForceDirectedLayout({ randomNumberGenerator: null, maxIterations: 400 }),
      "LayoutCompleted": e => mergeLinksAtPorts(e.diagram.nodes),
      "draggingTool.doActivate": function() {
        go.DraggingTool.prototype.doActivate.call(this);
        this.draggedParts.iteratorKeys.each(n => {
          if (!(n instanceof go.Node)) return;
          n.findLinksConnected().each(l => {
            l.fromSpot = go.Spot.Default;
            l.toSpot = go.Spot.Default;
          });
        });
      },
      "SelectionMoved": e => mergeLinksAtPorts(e.diagram.nodes),
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { width: 120, height: 60, locationSpot: go.Spot.Center },
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.Shape, "RoundedRectangle",
      {
        fill: "white", stroke: "gray", strokeWidth: 3,
        portId: "",
        fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides
      }),
    $(go.TextBlock,
      new go.Binding("text"))
  );

myDiagram.linkTemplate =
  $(go.Link,
    { routing: go.Link.AvoidsNodes, corner: 10 },
    $(go.Shape, { stroke: "orange", strokeWidth: 3 }),
    $(go.TextBlock, { segmentIndex: 0, segmentOffset: new go.Point(-10, 0) },
      new go.Binding("text", "fromPort")),
    $(go.TextBlock, { segmentIndex: -1, segmentOffset: new go.Point(10, 0) },
      new go.Binding("text", "toPort"))
  );

function mergeLinksAtPorts(nodes) {
  const map = new go.Map();
  nodes.each(n => {
    if (!(n instanceof go.Node)) return;
    map.clear();
    n.findLinksConnected().each(l => {
      // can we assume no reflexive links?
      if (l.fromNode === n) {
        const fid = l.data.fromPort;
        let arr = map.get(fid);
        if (!arr) map.set(fid, arr = []);
        arr.push(l);
      } else if (l.toNode === n) {
        const tid = l.data.toPort;
        let arr = map.get(tid);
        if (!arr) map.set(tid, arr = []);
        arr.push(l);
      }
    });
    map.each(kvp => {
      const id = kvp.key;
      const arr = kvp.value;
      if (!arr || arr.length <= 1) return;
      const first = arr[0];
      let spot;
      if (first.fromNode === n) {
        spot = computeSpot(n, first.getPoint(0));
      } else if (first.toNode === n) {
        spot = computeSpot(n, first.getPoint(first.pointsCount-1));
      }
      arr.forEach(link => {
        if (link.fromNode === n) {
          link.fromSpot = spot;
        } else if (link.toNode === n) {
          link.toSpot = spot;
        }
      });
    })
  });
}

function computeSpot(node, pt) {
  const b = node.getDocumentBounds();
  return new go.Spot(
      Math.max(0, Math.min((pt.x - b.x) / (b.width || 1), 1)),
      Math.max(0, Math.min((pt.y - b.y) / (b.height || 1), 1))
    );
}

const nda = [
  {key: "system1", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system2", portArray : [{portId : 0}, {portId : 1}, {portId : 2}]},
  {key: "system3", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system4", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}]},
  {key: "system5", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system6", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}, {portId : 4}]},
  {key: "system7", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system8", portArray : [{portId : 0}, {portId : 1}]},
  {key: "system9", portArray : [{portId : 0}, {portId : 1}, {portId : 2}, {portId : 3}]},
  {key: "system10", portArray : [{portId : 0}, {portId : 1}]}
];
const lda = [
  {"from":"system2","fromPort":0,"to":"system8","toPort":0},
  {"from":"system2","fromPort":2,"to":"system9","toPort":2},
  {"from":"system3","fromPort":0,"to":"system9","toPort":1},
  {"from":"system3","fromPort":1,"to":"system6","toPort":1},
  {"from":"system4","fromPort":2,"to":"system6","toPort":0},
  {"from":"system5","fromPort":0,"to":"system10","toPort":1},
  {"from":"system5","fromPort":1,"to":"system9","toPort":3},
  {"from":"system6","fromPort":0,"to":"system4","toPort":0},
  {"from":"system6","fromPort":2,"to":"system1","toPort":0},
  {"from":"system6","fromPort":3,"to":"system10","toPort":1},
  {"from":"system6","fromPort":4,"to":"system4","toPort":0},
  {"from":"system7","fromPort":0,"to":"system2","toPort":1},
  {"from":"system7","fromPort":1,"to":"system4","toPort":1},
  {"from":"system8","fromPort":0,"to":"system1","toPort":1},
  {"from":"system9","fromPort":0,"to":"system8","toPort":0},
  {"from":"system9","fromPort":2,"to":"system1","toPort":0},
  {"from":"system10","fromPort":1,"to":"system9","toPort":2}
];
myDiagram.model = new go.GraphLinksModel(nda, lda);
  </script>
</body>
</html>

2 posts were split to a new topic: Routing of many links between nodes that are close to each other