The issue with two types of ports

I have 2 elements. Each element has 2 ports of different type. The code looks as following:

myDiagram.linkTemplate =
    $(go.Link,
    {
        relinkableFrom: true, relinkableTo: true,
        selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
        shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "black"
    },
    new go.Binding("isShadowed", "isSelected").ofObject(),
    $(go.Shape,
        { name: "SHAPE", strokeWidth: 2, stroke: black }));

function portStyle0(input) {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        fromLinkable: !input,
        toLinkable: input,
        cursor: "pointer"
    };
}

function portStyle1() {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        toLinkable: true,
        cursor: "pointer",
        fromLinkable: true,
        fromSpot: go.Spot.TopBottomSides,
        toSpot: go.Spot.TopBottomSides
    };
}

var image4Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(false),  // the only port
        { portId: "", alignment: new go.Spot(0.12, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_1.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "", alignment: new go.Spot(0.12, 0) })
    );

var image5Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(true),  // the only port
        { portId: "", alignment: new go.Spot(0.525, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_2.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "", alignment: new go.Spot(0.525, 0) })
    );

When I try to connect upper ports from left to right element I’ve got the following diagram (correct!):

When I remove lower ports I’ve got the following diagram (incorrect!):

I need the elements with different types of ports, but I’m not sure what’s wrong in my case.

You’ve got a few things you need to fix here.

  1. Make sure each port on a node is given a different portId, not just “”.
  2. Ensure you are setting the linkFromPortIdProperty and linkToPortIdProperty on your Model.
  3. Your portStyle0 function doesn’t specify fromSpot or toSpot, so of course the link is going to take the shortest path when connecting the top ports.

This is all covered in the intro to ports.

Regarding 2), I can’t set those properties on model because I write electrical schema editor where end user picks up elements from palette and drop them to diagram. He can draw the connection lines wherever he wants.

I’ve tried this:

function portStyle0(input) {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        fromLinkable: !input,
        toLinkable: input,
        cursor: "pointer",
        fromSpot: go.Spot.TopLeft,
        toSpot: go.Spot.TopRight
    };
}

function portStyle1() {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        toLinkable: true,
        cursor: "pointer",
        fromLinkable: true,
        fromSpot: go.Spot.TopBottomSides,
        toSpot: go.Spot.TopBottomSides
    };
}

var image4Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(false),  // the only port
        { portId: "1", alignment: new go.Spot(0.12, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_1.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "2", alignment: new go.Spot(0.12, 0) })
    );

var image5Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(true),  // the only port
        { portId: "3", alignment: new go.Spot(0.525, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_2.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "4", alignment: new go.Spot(0.525, 0) })
    );

And got this:

Did you try setting those properties? You need to. They don’t tell links which ports to use, they just identify the data property names so that the link data can keep track of ports.

...
linkFromPortIdProperty: "fromPort",  // required information:
linkToPortIdProperty: "toPort",      // identifies data property names
...

How can I write it to model? What’s the syntax?

I don’t have any model. The end user is drawing electrical schema and after he finishes he can save that model.

You mean you initially have no nodes or links? Then you can just start with an empty model.

myDiagram.model =
  $(go.GraphLinksModel,
    { linkFromPortIdProperty: "fromPort", linkToPortIdProperty: "toPort" });

I saw it, but I don’t have in code nodeDataArray and linkDataArray. I don’t need them because the end user draws the diagram.

I just edited my previous reply. You can initialize a model without providing nodeDataArray or linkDataArray.

In that case I’ve got this, which is incorrect because of small extra lines on both sides of connection line.

You set the fromSpot to TopLeft and toSpot to TopRight. It comes out the top left of the from port and goes in the top right of the to port, exactly as you defined it.

You need to be more careful in defining your templates.

No. I forgot to show port’s style code that fits to last screen shot. I’ve set fromSpot to “go.Spot.Left” and toSpot to “go.Spot.Right”.

And if I set fromSpot to “go.Spot.TopLeft” and toSpot to “go.Spot.TopRight”, the diagram looks as following:

How to overcome this issue?

Here’s the solution:

myDiagram.linkTemplate =
    $(go.Link,
    {
        relinkableFrom: true, relinkableTo: true,
        selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
        shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "black"
    },
    new go.Binding("isShadowed", "isSelected").ofObject(),
    $(go.Shape,
        { name: "SHAPE", strokeWidth: 2, stroke: black }));

function portStyle0(input) {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        fromLinkable: !input,
        toLinkable: input,
        cursor: "pointer"
    };
}

function portStyle1() {
    return {
        desiredSize: new go.Size(3, 3),
        fill: "black",
        toLinkable: true,
        cursor: "pointer",
        fromLinkable: true,
        fromSpot: go.Spot.TopBottomSides,
        toSpot: go.Spot.TopBottomSides
    };
}

var image4Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(false),  // the only port
        { portId: "1", alignment: new go.Spot(0.12, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_1.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "2", alignment: new go.Spot(0.12, 0) })
    );

var image5Template =
    $(go.Node, "Vertical", nodeStyle(),
    $(go.Shape, "Rectangle", portStyle0(true),  // the only port
        { portId: "3", alignment: new go.Spot(0.525, 0) }),
    $(go.Picture, "Images/ElectricalElements/Sec_2.svg"),
    $(go.Shape, "Rectangle", portStyle1(),  // the only port
        { portId: "4", alignment: new go.Spot(0.525, 0) })
    );

It means we don’t need to set fromSpot and toSpot settings on portStyle0 at all.