Links Alignment issue and overlapping issue

Hi All, I’m trying to create Network Plumbing Diagrams using GoJS. im able to create nodes and give connections between ports but im getting bad alignment and few links are getting overlapped which is getting difficult to understand which port is connecting to which port of node as shown in attached image.i m looking for proper spacing between links with proper alignment.Also i tried by creating Custom Link and overiding computeCurviness,computeEndSegmentLength,hasCurviness methods.i really want to understand how curves are getting calculated and how to route a link without overlapping and with some gap between links.Can i get any suggestions please?

      // an orthogonal link template, reshapable and relinkable
      myDiagram.linkTemplate =
        $(CustomLink,  // defined below
          {
            routing: go.Link.AvoidsNodes,
            corner: 5,
            curve: go.Link.JumpGap,
            reshapable: true,
            resegmentable: true,
            relinkableFrom: true,
            relinkableTo: true
          },
          new go.Binding("points").makeTwoWay(),
          $(go.Shape, { stroke: "#2F4F4F", strokeWidth: 2 })
        );
       / This custom-routing Link class tries to separate parallel links from each other.
    // This assumes that ports are lined up in a row/column on a side of the node.
    function CustomLink() {
      go.Link.call(this);
    };
    go.Diagram.inherit(CustomLink, go.Link);

    CustomLink.prototype.findSidePortIndexAndCount = function(node, port) {
      var nodedata = node.data;
     var len;
      if (nodedata !== null) {
//numberOfPorts is the field which we are maintaining externally
           len=nodeData["numberOfPorts"];
           return [Number(port.portId),len];
      }
      return [-1, len];
    };

    CustomLink.prototype.computeEndSegmentLength = function(node, port, spot, from) {
      var esl = go.Link.prototype.computeEndSegmentLength.call(this, node, port, spot, from);
      var other = this.getOtherPort(port);
      if (port !== null && other !== null) {
        var thispt = port.getDocumentPoint(this.computeSpot(from));
        var otherpt = other.getDocumentPoint(this.computeSpot(!from));
        if (Math.abs(thispt.x - otherpt.x) > 20 || Math.abs(thispt.y - otherpt.y) > 20) {
          var info = this.findSidePortIndexAndCount(node, port);
          var idx = info[0];
          var count = info[1];
          if (otherpt.x < thispt.x) {
              return esl +![IMG_20200825_150850|690x314](upload://tVeoe5pLHjx03lincgrS6BQ3aJi.jpeg)  idx * 30;
            } else {
              return esl + (count - idx + 1) * 30;
            }
         }
      }
      return esl;
    };

    CustomLink.prototype.hasCurviness = function() {
      if (isNaN(this.curviness)) return true;
      return go.Link.prototype.hasCurviness.call(this);
    };

    CustomLink.prototype.computeCurviness = function() {
      if (isNaN(this.curviness)) {
        var fromnode = this.fromNode;
        var fromport = this.fromPort;
        var fromspot = this.computeSpot(true);
        var frompt = fromport.getDocumentPoint(fromspot);
        var tonode = this.toNode;
        var toport = this.toPort;
        var tospot = this.computeSpot(false);
        var topt = toport.getDocumentPoint(tospot);
        if (Math.abs(frompt.x - topt.x) > 20 || Math.abs(frompt.y - topt.y) > 20) {
          if ((fromspot.equals(go.Spot.Left) || fromspot.equals(go.Spot.Right)) &&
            (tospot.equals(go.Spot.Left) || tospot.equals(go.Spot.Right))) {
            var fromseglen = this.computeEndSegmentLength(fromnode, fromport, fromspot, true);
            var toseglen = this.computeEndSegmentLength(tonode, toport, tospot, false);
            var c = (fromseglen - toseglen) / 2;
            if (frompt.x + fromseglen >= topt.x - toseglen) {
              if (frompt.y < topt.y) return c;
              if (frompt.y > topt.y) return -c;
            }
          } else if ((fromspot.equals(go.Spot.Top) || fromspot.equals(go.Spot.Bottom)) &&
            (tospot.equals(go.Spot.Top) || tospot.equals(go.Spot.Bottom))) {
            var fromseglen = this.computeEndSegmentLength(fromnode, fromport, fromspot, true);
            var toseglen = this.computeEndSegmentLength(tonode, toport, tospot, false);
            var c = (fromseglen - toseglen) / 2;
            if (frompt.x + fromseglen >= topt.x - toseglen) {
              if (frompt.y < topt.y) return c;
              if (frompt.y > topt.y) return -c;
            }
          }
        }
      }
      return go.Link.prototype.computeCurviness.call(this);
    };
    // end CustomLink class

Did you manually adjust the routes of the links in your screenshot? If so, what did it look like before that? What were the most serious problems?

Hi Walter, no im not adjusting manually ,i implemented customLink and tried to override the go.Link methods ```
computeCurviness

example: second link from left and second link from right is getting overlapped

Other example issue image,we can see red and black color links are getting overlapped horizontally and vertically without space between those links.how can i arrange these links and make all connection visible clearly with proper spacing ?

There isn’t a perfect solution. But you can try this: Extending Dynamic Ports Link Routing Overlapping Issue

Hmmm, you might also want to increase the space around the nodes so that the AvoidsNodes routing doesn’t route links so close to the nodes. Set { avoidableMargin: 20 } on your node template(s).

yes i went through that issue chat but i’m unable to find AvoidsLinksRouter.js this file which they used.this link https://gojs.net/temp/ is showing empty screen. can you please send that sample file?

That file should be in that directory.

I cannot find anything in this https://gojs.net/temp/ as shown in Attached screenshot.

The directory is not readable/executable. Go to the file directly.

Thanks for the update Walter, that sample code is working fine but still i have small issue with spacing between vertical lines as shown in attached image.(between second link from left and second link from right their is no gap,yes they are not overlapping but soo close to each other).
Is there any way to add padding or margin between links to create some gap?

Sorry, but the AvoidsLinksRouter at present does not insert additional corners (i.e. additional pairs of points).

yes i can completely understand what you are saying, but is there any other way to recreate the route of link by adding points if required when links are too close to each other because this is very important bug for our application ?..since it is connection between two different devices, connections(links) should be clearly visible and unique.

Can you change the x position of the nodes?

Unrelated, but I am guessing that you haven’t increased the Node.avoidableMargin as I suggested.

stencilsMap = new go.Map(); 
var $ = go.GraphObject.make;  // for conciseness in defining templates
	var nodeSelectionAdornmentTemplate =
	    $(go.Adornment, "Auto",
	        $(go.Shape, { fill: null, stroke: "deepskyblue", strokeWidth: 3, strokeDashArray: [8, 4] }),
	        $(go.Placeholder)
	    );
	var nodeResizeAdornmentTemplate =
	    $(go.Adornment, "Spot",
	        { locationSpot: go.Spot.Right },
	        $(go.Placeholder),
	        $(go.Shape, { alignment: go.Spot.TopLeft, cursor: "nw-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { alignment: go.Spot.Top, cursor: "n-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { alignment: go.Spot.TopRight, cursor: "ne-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),

	        $(go.Shape, { alignment: go.Spot.Left, cursor: "w-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { alignment: go.Spot.Right, cursor: "e-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),

	        $(go.Shape, { alignment: go.Spot.BottomLeft, cursor: "se-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { alignment: go.Spot.Bottom, cursor: "s-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { alignment: go.Spot.BottomRight, cursor: "sw-resize", desiredSize: new go.Size(15, 15), fill: "lightblue", stroke: "deepskyblue" })
	    );
	var nodeRotateAdornmentTemplate =
	    $(go.Adornment,
	        { locationSpot: go.Spot.Center, locationObjectName: "CIRCLE" },
	        $(go.Shape, "Circle", { name: "CIRCLE", cursor: "pointer", desiredSize: new go.Size(18, 18), fill: "lightblue", stroke: "deepskyblue" }),
	        $(go.Shape, { geometryString: "M3.5 7 L3.5 30", isGeometryPositioned: true, stroke: "deepskyblue", strokeWidth: 3, strokeDashArray: [8, 4] })
	    );
 var V_PPPole =
        $(go.Node, "Viewbox",
            { selectable: true, selectionAdornmentTemplate: nodeSelectionAdornmentTemplate },
            { resizable: true, minSize: new go.Size(40, 60) },
            { minLocation: new go.Point(0, rfds.common.diagramHeight-(rfds.common.diagramHeight-10)), maxLocation: new go.Point(rfds.genric.baseTemplateWidth-300, rfds.common.diagramHeight-(rfds.common.diagramHeight-10)) },
            { rotatable: true, rotateAdornmentTemplate: nodeRotateAdornmentTemplate },
            new go.Binding("position", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            
            $(go.Panel, "Spot",
                $(go.Shape, "Rectangle",
                    { fill: "whitesmoke", width: 100, height: rfds.genric.antennaHeight, strokeWidth:rfds.genric.defaultstrokeWidth, name:"size" }
                ),
		    	$(go.TextBlock, { font: rfds.genric.positionText, stroke: '#333',
		    		alignment: new go.Spot(0.5,0,5,-85), width: 130, height: 20,editable:true,text:"Position",name:"position"},
		    		new go.Binding("text","positionName")
		    	),
                $(go.Shape, "Rectangle",
                    rfds.getPortProperties(rfds.genric.blue, "1", go.Spot.Bottom, go.Spot.Bottom, [0.5, 1, 0, -17], [30, 30]),
                ),
                $(go.TextBlock,
                    { font: "bold 16px sans-serif", stroke: '#333', alignment: new go.Spot(0.5, 1, 0, -17), text: "L0" }),

                $(go.TextBlock,
                    { margin: 8, font: rfds.genric.textFont18pxBold,name:"model",
                	stroke: '#333',textAlign:"center", width: 100, alignment: new go.Spot(0.5, 0, 0, 30),text:"V Pole" },
                    new go.Binding("text","modelName"))

            ));
stencilsMap.add("V-PPPole", V_PPPole);
stencilsMap.add("", myDiagram.nodeTemplate);
myDiagram.nodeTemplateMap = stencilsMap;

Im using this kind of nodeTemplate for myDiagram, can you please tell me where should i add that avoidableMargin?

okay i just added in Node object and i got this result…
i see the horizontal links are totally overlapping. can you please tell me what should i do here?Im using the same file AvoidLinksRouter.js but still same issue like this for some casess!


	var ERIC_8843 = $(go.Node, "Viewbox",
			{avoidableMargin:30},
		{ selectable: true, selectionAdornmentTemplate: nodeSelectionAdornmentTemplate },
		{ resizable: true, resizeAdornmentTemplate: nodeResizeAdornmentTemplate, minSize: new go.Size(40, 60) },
		{ rotatable: true, rotateAdornmentTemplate: nodeRotateAdornmentTemplate },
		{ minLocation: new go.Point(0, diagramHeight-(diagramHeight-1100)), maxLocation: new go.Point(baseTemplateWidth-300, diagramHeight-200) },
		new go.Binding("position", "loc", go.Point.parse),
		
		$(go.Panel, "Spot",
			$(go.Shape, "Rectangle",
				{ desiredSize: new go.Size(242,120), fill: green, strokeWidth: strokeWidthRadio, name:"size"},
				new go.Binding("strokeDashArray", "dashLines")
			),
			$(go.TextBlock,
				{ margin: 8, font: rfds.ericson.textFontForTitle, stroke: '#333',textAlign:"center", alignment: new go.Spot(0.5, 0.5, 0, 0) },
				new go.Binding("text" , "modelName")),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 17, 17), width: 30, height: 30,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "1", fromLinkable: true, toLinkable: true, cursor: "pointer", strokeWidth: 0.5
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: rfds.ericson.textFont, stroke: '#333', text: "A", alignment: new go.Spot(0, 0, 14, 16) }),


			$(go.Shape, "Rectangle",
				{
					fill: blue, alignment: new go.Spot(0, 0, 47, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "2", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "B", alignment: new go.Spot(0, 0, 49, 17) }),



			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 77, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "3", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "C", alignment: new go.Spot(0, 0, 81, 17) }),


			$(go.Shape, "Rectangle",
				{
					fill: blue, alignment: new go.Spot(0, 0, 107, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "4", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font:textFont, stroke: '#333', text: "D", alignment: new go.Spot(0, 0, 110, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 137, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "5", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "E", alignment: new go.Spot(0, 0, 140, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: blue, alignment: new go.Spot(0, 0, 167, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "6", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "F", alignment: new go.Spot(0, 0, 170, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 197, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "7", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "G", alignment: new go.Spot(0, 0, 200, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill:blue, alignment: new go.Spot(0, 0, 227, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "8", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "H", alignment: new go.Spot(0, 0, 230, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0.6, 1, 36, -17), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "i", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: textFont, stroke: '#333', text: "i", alignment: new go.Spot(0.6, 1, 37, -17) }),


			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0.6, 1, 76, -17), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "o", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: rfds.ericson.textFont, stroke: '#333', text: "o", alignment: new go.Spot(0.6, 1, 77, -17) }),



			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0, 1, 16, -16), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "OUT", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 0, font: textFontBig, stroke: '#333', text: "OUT", alignment: new go.Spot(0, 1, 16, -16) }),


			$(go.Shape, "Rectangle",
				{
					fill: green, alignment: new go.Spot(0, 1, 47, -16), width: 30, height: 20, strokeWidth: 0,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "AISG", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),

			$(go.TextBlock,
				{ margin: 20, font: textFontBig, stroke: '#333', text: "AISG", alignment: new go.Spot(0, 1, 50, -16) })

		)
	);

Can you change the x position of the nodes?–> yes we can adjust with minimal change, but can you please tell me how to adjust it dynamically with least difference,for example let’s say i have x value as 100 and then im making value as 105 or 104 that is fine,since i just want to show links unique.

What is your link template? If you are using the AvoidsLinksRouter, I suggest that you use the regular Link class, not the custom class taken from the Dynamic Ports sample.

This is my LinkTemplate ,stencil Object,DiagramObject.Links are getting disturbed

 // but use the default Link template, by not setting Diagram.linkTemplate
 var myRouter = new AvoidsLinksRouter();
  
  palette = new go.Palette("myPaletteDiv");
  myDiagram =
    $(go.Diagram, "myDiagramDiv", {  // must name or refer to the DIV HTML
      initialAutoScale: go.Diagram.Uniform,
      "LayoutCompleted": function(e) { myRouter.avoidOrthogonalOverlaps(e.diagram.links); }
    },
      {
        grid: $(go.Panel, "Grid",
          $(go.Shape, "LineH", { stroke: "whitesmoke", strokeWidth: 0.5 }),
          $(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5, interval: 10 }),
          $(go.Shape, "LineV", { stroke: "whitesmoke", strokeWidth: 0.5 }),
          $(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5, interval: 10 }),
        ),
        draggingTool: new GuidedDraggingTool(),  // defined in GuidedDraggingTool.js
        "draggingTool.horizontalGuidelineColor": "black",
        "draggingTool.verticalGuidelineColor": "black",
        "draggingTool.centerGuidelineColor": "green",
        "draggingTool.guidelineWidth": 1.5,
        "draggingTool.dragsLink": true,
        "draggingTool.isGridSnapEnabled": true,
        "linkingTool.isUnconnectedLinkValid": true,
        "linkingTool.portGravity": 20,
        "relinkingTool.isUnconnectedLinkValid": true,
        "relinkingTool.portGravity": 20,
        "relinkingTool.fromHandleArchetype":
          $(go.Shape, "Diamond", { segmentIndex: 0, cursor: "pointer", desiredSize: new go.Size(8, 8), fill: "tomato", stroke: "darkred" }),
        "relinkingTool.toHandleArchetype":
          $(go.Shape, "Diamond", { segmentIndex: -1, cursor: "pointer", desiredSize: new go.Size(8, 8), fill: "darkred", stroke: "tomato" }),
        "linkReshapingTool.handleArchetype":
          $(go.Shape, "Diamond", { desiredSize: new go.Size(7, 7), fill: "lightblue", stroke: "deepskyblue" }),
        "rotatingTool.handleAngle": 270,
        "rotatingTool.handleDistance": 30,
        "rotatingTool.snapAngleMultiple": 15,
        "rotatingTool.snapAngleEpsilon": 15,
        "undoManager.isEnabled": true
      }, {
        mouseDrop: function (e) {
        
        }
      });
  myDiagram.linkTemplate =
    $(go.Link,
      {
        routing: go.Link.AvoidsNodes,// routing: go.Link.Orthogonal,  Orthogonal routing
        corner: 5,  // with rounded corners
        curve: go.Link.JumpOver,
        relinkableFrom: true, relinkableTo: true,
        reshapable: true,
        resegmentable: true,
      },    // little "hops" in the path of an orthogonal link that crosses another orthogonal link
      new go.Binding("points").makeTwoWay(),
      $(go.Shape, { isPanelMain: true },
        new go.Binding("stroke", "color"),  // shape.stroke = data.color
        new go.Binding("strokeWidth", "thick"),// shape.strokeWidth = data.thick
        new go.Binding("fill", "fill"),
        new go.Binding("isPanelMain", "isPanelMain"),
      ),
      $(go.Shape,
        { toArrow: "" }, { isPanelMain: true },
        new go.Binding("toArrow", "toArrow"),  // shape.stroke = data.color 
        new go.Binding("angle", "angle"),
        new go.Binding("strokeWidth", "thick"),
        new go.Binding("fill", "fill"),
        new go.Binding("stroke", "color")
      ),
    );

	var ERIC_8843 = $(go.Node, "Viewbox",
			{avoidableMargin:20},
		{ selectable: true, selectionAdornmentTemplate: nodeSelectionAdornmentTemplate },
		{ resizable: true, resizeAdornmentTemplate: nodeResizeAdornmentTemplate, minSize: new go.Size(40, 60) },
		{ rotatable: true, rotateAdornmentTemplate: nodeRotateAdornmentTemplate },
		{ minLocation: new go.Point(0, diagramHeight-(common.diagramHeight-1100)), maxLocation: new go.Point(genric.baseTemplateWidth-300, common.diagramHeight-200) },
		new go.Binding("position", "loc", go.Point.parse),
		
		$(go.Panel, "Spot",
			$(go.Shape, "Rectangle",
				{ desiredSize: new go.Size(242,120), fill: ericson.green, strokeWidth: ericson.strokeWidthRadio, name:"size"},
				new go.Binding("strokeDashArray", "dashLines")
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFontForTitle, stroke: '#333',textAlign:"center", alignment: new go.Spot(0.5, 0.5, 0, 0) },
				new go.Binding("text" , "modelName")),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 17, 17), width: 30, height: 30,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "1", fromLinkable: true, toLinkable: true, cursor: "pointer", strokeWidth: 0.5
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "A", alignment: new go.Spot(0, 0, 14, 16) }),


			$(go.Shape, "Rectangle",
				{
					fill: ericson.blue, alignment: new go.Spot(0, 0, 47, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "2", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "B", alignment: new go.Spot(0, 0, 49, 17) }),



			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 77, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "3", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "C", alignment: new go.Spot(0, 0, 81, 17) }),


			$(go.Shape, "Rectangle",
				{
					fill: ericson.blue, alignment: new go.Spot(0, 0, 107, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "4", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "D", alignment: new go.Spot(0, 0, 110, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 137, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "5", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "E", alignment: new go.Spot(0, 0, 140, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: ericson.blue, alignment: new go.Spot(0, 0, 167, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "6", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "F", alignment: new go.Spot(0, 0, 170, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: lightOrange, alignment: new go.Spot(0, 0, 197, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "7", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "G", alignment: new go.Spot(0, 0, 200, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: ericson.blue, alignment: new go.Spot(0, 0, 227, 17), width: 30, height: 30, strokeWidth: 0.5,
					fromSpot: go.Spot.Top, toSpot: go.Spot.Top,
					portId: "8", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "H", alignment: new go.Spot(0, 0, 230, 17) }),

			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0.6, 1, 36, -17), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "i", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "i", alignment: new go.Spot(0.6, 1, 37, -17) }),


			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0.6, 1, 76, -17), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "o", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 8, font: ericson.textFont, stroke: '#333', text: "o", alignment: new go.Spot(0.6, 1, 77, -17) }),



			$(go.Shape, "Rectangle",
				{
					fill: "white", alignment: new go.Spot(0, 1, 16, -16), width: 30, height: 30, strokeWidth: 0.6,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "OUT", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),
			$(go.TextBlock,
				{ margin: 0, font: ericson.textFontBig, stroke: '#333', text: "OUT", alignment: new go.Spot(0, 1, 16, -16) }),


			$(go.Shape, "Rectangle",
				{
					fill: ericson.green, alignment: new go.Spot(0, 1, 47, -16), width: 30, height: 20, strokeWidth: 0,
					fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom,
					portId: "AISG", fromLinkable: true, toLinkable: true, cursor: "pointer"
				}
			),

			$(go.TextBlock,
				{ margin: 20, font: ericson.textFontBig, stroke: '#333', text: "AISG", alignment: new go.Spot(0, 1, 50, -16) })

		)
	);

That’s very odd – I cannot explain why those horizontal segments are going through the green nodes. But at least there seem to be no horizontal segments that overlap each other.

if we are not using this AvoidsLinksRouter, those horizontal segments are not going through the green nodes… is there any way to fix that?