How to position dynamic ports added to group?


#1

Hi,
I’d like to create X number of ports on group, depending on how much links are connected to nodes inside the said group. I drew inspiration from these samples:
http://gojs.net/latest/samples/dynamicPorts.html - I learned how to add a port dynamically
https://gojs.net/latest/samples/draggablePorts.html - I “borrowed” only the shape of the port.
However, in my diagram, the ports seem to be located one over the other, and their position on the group ins’t really good.
Here is my template code:

 var getPortStyle = function (arrayName) {

    var position = arrayName === 'inputsArray' ? new go.Spot(0, 0.5) : new go.Spot(1, 0.5);

    return $(go.Panel, 'Spot', { alignment: position },
        new go.Binding('itemArray', arrayName),
        {
            itemTemplate: $(go.Panel, {
                    fromSpot: go.Spot.Right,
                    fromLinkable: arrayName !== 'inputsArray',
                    toSpot: go.Spot.Left,
                    toLinkable: arrayName === 'inputsArray',
                    cursor: 'pointer',
                    portId: ''
                },
                new go.Binding('portId', 'portId'),
                $(go.Shape, {

                    fill: 'lightgray',
                    stroke: 'gray',
                    geometryString: 'F1 m 0,0 l 5,0 1,4 -1,4 -5,0 1,-4 -1,-4 z',
                    spot1: new go.Spot(0, 0, 5, 1),
                    spot2: new go.Spot(1, 1, -5, 0)
                })
            )
        }
    );
  };

 $(go.Group, go.Panel.Auto, {
            isSubGraphExpanded: false,
            ungroupable: true
        },
        $(go.Shape, group.shape, group.details),
        getPortStyle(groupPortsNames.in),
        $(go.Placeholder, {alignment: go.Spot.TopLeft}),
        $(go.TextBlock, textBlock,
            new go.Binding('text', 'text')));

Is there any other example that may be helpful?


#2

Remember that “Spot” Panels require a main element about which the other ellements are arranged via the GraphObject.alignment property. Read http://gojs.net/latest/intro/panels.html#SpotPanels for more discussion.

In your case the Spot Panel has no elements in it other than those generated for the items in the Panel.itemArray. If there is no main element already there in the Spot Panel, it will use the first element, which in your case will be the first port. So all of the ports will be arranged about the first port.


#3

I assume a shape could be used as a main element, but the problem still persists… Here is the modification I did. The ports are added in the itemArray of the groups data object. However, they still seem to be over each other and placed in the center of the group…

var getPortStyle = function (arrayName) {

    var position = arrayName === 'inputsArray' ? new go.Spot(0, 0.5) : new go.Spot(1, 0.5);

    return $(go.Panel, 'Spot', { alignment: position },
    $(go.Shape, 'Rectangle', { fill: null }),
    new go.Binding('itemArray', arrayName),
    {
        itemTemplate: $(go.Panel, {
                fromSpot: go.Spot.Right,
                fromLinkable: arrayName !== 'inputsArray',
                toSpot: go.Spot.Left,
                toLinkable: arrayName === 'inputsArray',
                cursor: 'pointer',
                portId: ''
            },
            new go.Binding('portId', 'portId'),
            $(go.Shape, {

                fill: 'lightgray',
                stroke: 'gray',
                geometryString: 'F1 m 0,0 l 5,0 1,4 -1,4 -5,0 1,-4 -1,-4 z',
                spot1: new go.Spot(0, 0, 5, 1),
                spot2: new go.Spot(1, 1, -5, 0)
            })
        )
    }
    );
  };



$(go.Group, go.Panel.Auto, {
        isSubGraphExpanded: false,
        ungroupable: true
    },
    $(go.Shape, group.shape, group.details),
    getPortStyle(groupPortsNames.in),
    $(go.Placeholder, {alignment: go.Spot.TopLeft}),
    $(go.TextBlock, textBlock,
        new go.Binding('text', 'text')));

EDIT: Switching to a vertical panel, I am able to see multiple ports that are created… However, I still can’t get the ports to position on the far left side of the group (I imagined the ports visually partially outside of the group)… I’m thinking of switching to position panel and assigning the position of ports manually. What do you think?

EDIT2: After tinkering with it and another example, I’ve noticed that I missed mentioning an important piece of information. I’m using a rounded rectangle for the shape and I set parameter1 - this causes some extra space to be created between the side of the shape itself and the vertical panel I’m trying to position entirely left.


#4

I think the Dynamic Ports sample demonstrates what you want to do. Just change it to be a Group instead of a Node, and put the Placeholder inside the body. And delete all those elements that you do not need.


#5

Hi, Walter, tnx for the suggestion. I did that, and I wanted to ask something else. I removed the desiredSize property from the example, and everything works fine as long as I don’t have any ports to add. As soon as I add a port, the entire group becomes the size of the port. I assume that some inheritance is occurring? Can I do anything about that without setting a fixed size?


#6

If you don’t set the GraphObject.desiredSize (or width and height) of an object, it will get its natural size or its panel will impose a size. I don’t know what you have to be able to give a meaningful answer. Maybe you could post a simplified template, stripping out irrelevant details. Some screenshots wouldn’t hurt, either.


#7

Hi walter, thank you for your response. I think the simplest thing would is to just set minSize. The reason I asked in the first place was because I was confused as to why drawing a port would affect the size of the main shape.

     $(go.Group, 'Table',
        {
            isSubGraphExpanded: false,
            ungroupable: true,
            locationObjectName: 'BODY',
            locationSpot: go.Spot.Center,
            selectionObjectName: 'BODY'
        },
        $(go.Panel, 'Auto',
            {
                row: 1, column: 1,
                name: 'BODY',
                stretch: go.GraphObject.Fill, 
                //minSize: new go.Size(NaN; 50)
            },
            $(go.Shape, 'RoundedRectangle', { fill: 'blue', strokeWidth: 1.5 }),
            $(go.Placeholder, {alignment: go.Spot.TopLeft}),
            $(go.TextBlock, { font: '12pt Helvertica, Arial, sans-serif', margin: 10 },
                new go.Binding('text', 'text'))
        ),
        $(go.Panel, 'Vertical', { alignment: new go.Spot(0, 0.5, 10, 0) },
            new go.Binding('itemArray', 'inputsArray'),
            {
                row: 1, column: 0,
                itemTemplate: $(go.Panel,
                    {
                        _side: 'left',
                        fromSpot: go.Spot.Left, toSpot: go.Spot.Left,
                        fromLinkable: true, toLinkable: true,
                        cursor: 'pointer',
                        alignment: go.Spot.TopLeft
                    },
                    new go.Binding('portId', 'portId'),
                    $(go.Shape, 'Circle',
                        {
                            desiredSize: new go.Size(8, 8),
                            margin: new go.Margin(2, 0),
                            alignment: go.Spot.TopLeft,
                            fill: 'transparent'
                        })
                )
            }
        )
    );

So given this code (without setting minSize), it works as expected when there are no ports:

But the group looks like this:


when there is a port - the desiredSize of the port gets applied.
But as I said, i decided to use minSize for simplicity.


#8

2 posts were split to a new topic: Arranging variable number of ports into multiple rows