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

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.

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

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.

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?

We need to reproduce the problem first. If you can help with that…
Or we can try to do so on our own based on your screenshots.

Problem 1: Links are going on to nodes even after having routing: go.Link.AvoidsNodes in linkTemplate

Problem 2: Few Vertical links and Horizontal Links are too close to each other(Not Overlapping) and appearing like one link. So we need to create some padding or margin to links or we need to create extra points to enroute the link where we get proper gap between links to make individual links visible clearly.so how can we make this possible?

Note: we are not using customLink

Starting from the Dynamic Ports sample, and not using CustomLink, I am unable to reproduce the problem that you show with the horiziontal segment crossing over the two nodes.

Hi walter
when we are using myRouter for arranging links , AvoidNodes functionality is getting overridden
after Avoid Nodes , myRouter is getting executed and links are getting adjusted
so links are overlapping on the stencil. can you please tell me solution for this problem?