Gojs override the ports rules and draw incoming or outgoing link from the restricted ports

I have nodes with multiple ports and each node has some rules applied. There will be few ports of node which I don’t want to have outgoing links depending on node type and same way I don’t want to have incoming links to the port which are not allowed to accept incoming links.

Node with ports

Node has link going from below even though there are rules saying no link should go from below of this type of node, links can go out from only right side of the node.

as you can see when I am trying to create link manually it don’t let me select any other port except the ports on right which I want are only allowed.

On diagram initial layout gojs don’t respect applied rules and draw link from any port but I want gojs to draw link from only ports which are only allow each node as each node may have different rules depending on its type.

When I draw links manually rules work fine but for initial gojs layout it don’t work as I don’t want to set by myself but I want gojs to find best node out of the available (allowed ports, not restricted) ports and draw link from those.

/ ports
    for (let i = 1; i <= 12; i++) {
        const { fromLinkable, toLinkable } = this.getFromToEnabledPorts(comp.getAttribute("type"));
        data["canLinkFromPort" + i] = (fromLinkable as any).flat().includes(i.toString())
        data["canLinkToPort" + i] = (toLinkable as any).flat().includes(i.toString())
        data["port" + i + "Alignment"] = this.getPortSpot(i, goShapeType);
    }

   private makePort(portId: number): go.Shape {
       const fromSpot: go.Spot = this.getPortSpot(portId, null);
       return go.GraphObject.make(go.Shape, {
           cursor: "crosshair",
           fill: null,
           // fromLinkable: true,
           fromSpot,
           mouseEnter: () => {
               this.oldAnimation = this.animation;
               this.animation = false;
               this.goDiagram.allowLink = true;
           },
           mouseLeave: () => {
               this.goDiagram.allowLink = false;
               this.animation = this.oldAnimation;
           },
           portId: portId.toString(),
           stroke: null,
           // toLinkable: true,
           toSpot: fromSpot,
       },

           new go.Binding("fromLinkable", "canLinkFromPort" + portId),
           new go.Binding("toLinkable", "canLinkToPort" + portId),
       );
   }

   private getFromToEnabledPorts(nodeType) {
       const top = ["T1", "T2", "T3"]
       const right = ["R1", "R2", "R3"]
       const bottom = ["B1", "B2", "B3"]
       const left = ["L1", "L2", "L3"]
       let fromLinkable: Array<string[]>;
       let toLinkable: Array<string[]>;
       // Apply custom rules for enabling/disabling ports based on node type
       if (nodeType === "A") {
           // For "A" type: only enable bottom and right ports for outgoing
           fromLinkable = [right, bottom];
           // Enable top and left ports for incoming
           toLinkable = [left, top];
       } else if (nodeType === "B") {
           // For "B" type: only enable right ports for outgoing, left for incoming
           fromLinkable = [right];
           toLinkable = [left];
       } else if (nodeType === "C") {
           // For "C" type: only enable top and right ports for outgoing, bottom and left for incoming
           fromLinkable = [top, right, bottom];
           toLinkable = [left, top];
       }
       return { fromLinkable, toLinkable }
   }

really appreciate any help/suggestions @walter

Have you set GraphLinksModel.linkFromPortIdProperty and linkToPortIdProperty so that the model knows about port identifiers on link data objects?

If a link data object does not specify the Link.fromPortId or toPortId, it will choose the default Node.port which is the port whose id is “” (the empty string), and if there is no such element it uses the whole node.

Are you using a Diagram.layout? If so, what is its definition? It might be that the layout is assuming that everything is going downwards.

Yes I have set GraphLinksModel.linkFromPortIdProperty and linkToPortIdProperty but I set to and from port empty because I want gojs to handle the link routing by finding best port for to and from but I want it to use only those ports which are enabled not those which are disabled.

As in my question above there is image with round shape which has link from from bottom but bottom ports are disabled and only ports are allowed are on the right side of the node so I want gojs to choose from port from any of 3 ports on the right of the shape. Does it make sense?

There are many shapes with links coming out from above/right/left but all handled by gojs as I don’t tell any particular port to use but main idea is just gojs avoid disabled port and use allowed ones.

The built-in routing algorithms only work from port to port – they cannot decide which ports to use. Think of an arithmetic division operator – you wouldn’t want the diagram to swap the dividend and divisor arguments just to make the routes prettier!

If you don’t really care which port connects with which port, maybe you don’t want to use ports at all. You could use the “…Side” Spots to control which sides links can connect at.

Thanks @walter, Spot seems to be helpful in this case, but there is some case where I need to cover 3 sides of a node such as Top, Bottom, Right but Spot don’t provide option to cover all those at once like go.Spot.TopBottomRightSides but didn’t find any thing for that.

as you can see in below image there’s a link going from below to the node in the right but I want it to go from right but can’t set spot for three sides using any spot option.

File (3)

any idea what can i do for to cover this scenario?

The three-sided Spots are called “Not…Side”. Spot.NotLeftSide in your example.

Thanks @jhardy it worked.