Node Template with attribute for several ports advanced

Some time ago Walter gave me a solution to my problem

Now I have advanced version and I need to add a port orientation(side) attribute (left, right).

How to make changes to Walter’s code so that,
depending on the orientation of the attribute,
the ports have option to be situated on the left or right side and the description appears in the middle?
go1

What’s your basic plan? How close have you come so far?

I want to achieve what is in the picture. For now I have no idea how to do it.

What would the data be for that node?

The data below:
{
key: 1, text: “Alpha”, color: “lightblue”,
ports: [
{ id: “a1”, index: 0, text: “A”, color: “yellow”, side: “right” },
{ id: “a2”, index: 1, text: “A”, color: “yellow”, side: “right” },
{ id: “a3”, index: 2, text: “A”, color: “yellow”, side: “right” },
{ id: “a4”, index: 3, text: “A”, color: “yellow”, side: “right” },
{ id: “b1”, index: 4, text: “B”, color: “lightgreen”, side: “right” },
{ id: “b2”, index: 5, text: “B”, color: “lightgreen”, side: “right” },
{ id: “c1”, index: 6, text: “C”, color: “orange”, side: “right” },
{ id: “a11”, index: 0, text: “A”, color: “yellow”, side: “left” },
{ id: “a12”, index: 1, text: “A”, color: “yellow”, side: “left” },
{ id: “a13”, index: 2, text: “A”, color: “yellow”, side: “left” },
{ id: “b11”, index: 3, text: “B”, color: “lightgreen”, side: “left” },
]
}

Well, it’s easy to filter the ports for each side:

image

<!DOCTYPE html>
<html>

<head>
  <title>Grouped Ports</title>
  <!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
  <meta name="description" content="A Node whose lists of ports are grouped together.">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="../latest/release/go.js"></script>
  <script id="code">
    const $ = go.GraphObject.make;

    const myDiagram =
      new go.Diagram("myDiagramDiv");

    myDiagram.nodeTemplate =
      $(go.Node,
        $(go.Panel, "Table",
          $(go.Shape,
            { column: 1, columnSpan: 2, fill: "white", stretch: go.Stretch.Fill },
            new go.Binding("fill", "color")),
          $(go.Panel, "Table",
            { column: 0 },
            new go.Binding("itemArray", "ports", a => getPorts(a, true)),
            {
              itemTemplate:
                $(go.Panel, "Spot",
                  new go.Binding("portId", "id"),
                  new go.Binding("row", "index"),
                  { width: 30, height: 15 },
                  $(go.Shape,
                    { fill: "white" },
                    new go.Binding("fill", "color")),
                  $(go.TextBlock,
                    { margin: new go.Margin(1, 0, 0, 0) },
                    new go.Binding("text", "id"))
                )
            }
          ),
          $(go.Panel, "Table",
            { column: 1, alignment: go.Spot.Right, margin: 2 },
            new go.Binding("itemArray", "ports", a => convertPortsToAttributes(a, true)),
            {
              itemTemplate:
                $(go.Panel, "Auto",
                  new go.Binding("row", "index"),
                  { width: 30, height: 15 },
                  new go.Binding("height", "rows", r => r * 15),
                  $(go.Shape,
                    { fill: "white", stretch: go.Stretch.Fill },
                    new go.Binding("fill", "color")),
                  $(go.TextBlock,
                    { margin: new go.Margin(1, 0, 0, 0) },
                    new go.Binding("text"))
                )
            }
          ),
          $(go.Panel, "Table",
            { column: 2, alignment: go.Spot.Right, margin: 2 },
            new go.Binding("itemArray", "ports", a => convertPortsToAttributes(a, false)),
            {
              itemTemplate:
                $(go.Panel, "Auto",
                  new go.Binding("row", "index"),
                  { width: 30, height: 15 },
                  new go.Binding("height", "rows", r => r * 15),
                  $(go.Shape,
                    { fill: "white", stretch: go.Stretch.Fill },
                    new go.Binding("fill", "color")),
                  $(go.TextBlock,
                    { margin: new go.Margin(1, 0, 0, 0) },
                    new go.Binding("text"))
                )
            }
          ),
          $(go.Panel, "Table",
            { column: 3 },
            new go.Binding("itemArray", "ports", a => getPorts(a, false)),
            {
              itemTemplate:
                $(go.Panel, "Spot",
                  new go.Binding("portId", "id"),
                  new go.Binding("row", "index"),
                  { width: 30, height: 15 },
                  $(go.Shape,
                    { fill: "white" },
                    new go.Binding("fill", "color")),
                  $(go.TextBlock,
                    { margin: new go.Margin(1, 0, 0, 0) },
                    new go.Binding("text", "id"))
                )
            }
          ),
        )
      );

    function getPorts(arr, left) {
      const a2 = [];
      arr.forEach(port => {
        if (left && port.side !== "left") return;
        if (!left && port.side === "left") return;
        a2.push(port);
      });
      return a2;
    }

    function convertPortsToAttributes(arr, left) {
      const a2 = [];
      let prevText = "";
      arr.forEach(port => {
        if (left && port.side !== "left") return;
        if (!left && port.side === "left") return;
        if (port.text !== prevText) {
          a2.push({ index: port.index, rows: 1, text: port.text, color: port.color });
          prevText = port.text;
        } else {
          a2[a2.length - 1].rows++;
        }
      });
      return a2;
    }

    myDiagram.model = new go.GraphLinksModel({
      linkFromPortIdProperty: "fpid",
      linkToPortIdProperty: "tpid",
      nodeDataArray: [
        {
          key: 1, text: "Alpha", color: "lightblue",
          ports: [
            { id: "a1", index: 0, text: "A", color: "yellow", side: "right" },
            { id: "a2", index: 1, text: "A", color: "yellow", side: "right" },
            { id: "a3", index: 2, text: "A", color: "yellow", side: "right" },
            { id: "a4", index: 3, text: "A", color: "yellow", side: "right" },
            { id: "b1", index: 4, text: "B", color: "lightgreen", side: "right" },
            { id: "b2", index: 5, text: "B", color: "lightgreen", side: "right" },
            { id: "c1", index: 6, text: "C", color: "orange", side: "right" },
            { id: "a11", index: 0, text: "A", color: "yellow", side: "left" },
            { id: "a12", index: 1, text: "A", color: "yellow", side: "left" },
            { id: "a13", index: 2, text: "A", color: "yellow", side: "left" },
            { id: "b11", index: 3, text: "B", color: "lightgreen", side: "left" },
          ]
        }
      ]
    }
    );
  </script>
</body>

</html>

I know, but that’s not my goal.
I would like to do as in my drawing

You’ll need to make the filtering of data smarter. Sorry, I don’t have time now to do that.