Evenly distributed ports

Hey,

We have created a node with dynamic ports, which is referenced from this example. But I don’t know how to make these ports evenly distributed. For example, If we have two ports on the left side, the distance between ports should be 1/3 of the width length.

image

Instead of using a “Vertical” Panel to hold all of the ports that are on a side of the node, use a “Table” Panel, and make sure that that Panel is stretched vertically, instead of getting its natural height from the collection of elements that it has.

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

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

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      layout: $(go.LayeredDigraphLayout),
      "undoManager.isEnabled": true
    });

function makePort(id, input, row) {
  return $(go.Shape,
    {
      width: 7, height: 7,
      row: row,
      portId: id,
      fromSpot: input ? go.Spot.Default : go.Spot.Right,
      toSpot: input ? go.Spot.Left : go.Spot.Default
    });
}

myDiagram.nodeTemplate =
  $(go.Node, "Spot",
    $(go.Panel, "Auto",
      { width: 80, height: 80 },
      $(go.Shape,
        { fill: "lightgray" },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        new go.Binding("text"))
    ),
    $(go.Panel, "Table",
      { stretch: go.GraphObject.Vertical,
        alignment: go.Spot.Left, alignmentFocus: go.Spot.Right },
      makePort("A", true, 0),
      makePort("B", true, 1),
      makePort("C", true, 2)
    ),
    $(go.Panel, "Table",
      { stretch: go.GraphObject.Vertical,
        alignment: go.Spot.Right, alignmentFocus: go.Spot.Left },
      makePort("X", false, 0),
      makePort("Y", false, 1)
    )
  );

myDiagram.linkTemplate =
  $(go.Link,
    {
      curve: go.Link.Bezier,
      fromEndSegmentLength: 20, toEndSegmentLength: 20,
      relinkableFrom: true, relinkableTo: true,
      reshapable: true, resegmentable: true
    },
    $(go.Shape, { strokeWidth: 1.5 })
  );

myDiagram.model = new go.GraphLinksModel(
  {
    linkFromPortIdProperty: "fpid",
    linkToPortIdProperty: "tpid",
    nodeDataArray: [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
    ],
    linkDataArray: [
      { from: 1, fpid: "X", to: 2, tpid: "A" },
      { from: 1, fpid: "Y", to: 2, tpid: "B" },
      { from: 3, fpid: "X", to: 2, tpid: "C" }
    ]
  }
);
  </script>
</body>
</html>

produces:
image

Hey walter, currently it’s looking good, but I want the port location to be like that if we have three ports, the first port location is 1/4 of height, and the second one is 2/4 of height, the last is 3/4 of height, like below

image

If we have two ports, the first location is 1/3 of height , and second is 2/3 of height.
image

So you want to give each port different amounts of space? For example, with the policy that you are proposing, when there are two ports if each port were half the height of the node or a little less, then the ports would overlap each other.

Sorry, I don’t understand your explains, the policy is that each port has the same length from one side to another side, I have made a comparison, the left side is the current state, and the right side is the expected state.

image

each port has the same length from one side to another side

The default policy implemented by “Table” Panel for allocating extra space to each element is the same as it is in HTML tables – each element gets additional height depending on how tall it is. Since all of the ports have the same height, each port gets the same vertical space. As you can see, when there are three ports, there are four spaces. That is why they are positioned the way that they are.

My previous question involves what should happen when the ports are much taller than they are now in your screenshots. Let’s say each port of the three were a third of the height of the node. With our policy, the ports would not overlap; with your policy the ports would be too close to each other so they would overlap each other.

You could add a margin to the “Table” Panel. For your policy, the exact vertical value to provide would need to be computed depending on the height of the ports and their number. In my test, I found that for three ports setting { margin: new go.Margin(10, 0) } worked well. But the correct value will depend on the height of the node and the height of the ports and the number of ports.

My previous question involves what should happen when the ports are much taller than they are now in your screenshots. Let’s say each port of the three were a third of the height of the node. With our policy, the ports would not overlap; with your policy the ports would be too close to each other so they would overlap each other.

This would happen, But the port has the fixed size and wouldn’t be larger in the common case. Although setting the margin will make the example closed to the expected state, but it wouldn’t be the expected solution under unknown height/width and port numbers. I thought the computation is needed.

By the way, How can I use the ‘Table Panel’ example or manually computed position to dynamically generate the ports based on the node template?

I’m not sure I understand your question. You’ve seen the Dynamic Ports sample, in which a node data Array defines all of the ports on a side of the node. That way a single node template can not only support a variable number of ports, but also a dynamically varying number of ports for each specific Node.

solved by using computed spot and itemTemplate.