Can't figure out custom layout

I have objects with ports in a digraph layout. Ports need to be highlightable and selectable, and must belong to one of multiple groups (usually shown vertically on the left or right of the object). I’m trying to make each object a group and each port it’s own node to make use of the built-in highlight and select functionality available to nodes.

However it is not clear or obvious how to design a group template that contains specific subgroups of nodes. Panels cannot contain nodes. How do I make one group of ports sit on the left and one group of ports on the right? So much of this is not simple.

Have you seen this sample?

yes, that was the initial solution. however our layouts are suffering from lots of link crossover because the order of ports doesn’t matter. i was thinking that using groups of vertical nodes for ports would allow for them to be automatically arranged for optimal link layout.

this also does not let me use the built-in highlight and select functionality of nodes on ports.

i’m having a terrible time trying to custom position my port groups. the groups are also not behaving vertically even though i’m defining a vertical panel to contain the placeholder of nodes.

I’m not sure I understand your requirements. But you might want to look at this other sample:

as stated, i would like ports on left and right sides of my object (in ports, out ports). but i want each port to behave as a node. is that so complicated?

Have you actually looked at that sample?

yes i have looked at the sample. it is precisely how our templates are currently modeled and needs to be better.

the problem is that ports are shapes in all your examples. our ports have complex enough behavior that i believe warrants them being their own node.

one of several reasons: there can be a hundred ports on an object. the displayed order is fixed based on the order they are added to the member arrays. i would like the order to be variable, optimized to reduce link crossover. is this even possible?

The whole point of the Movable, Copyable, Deletable Ports sample is to demonstrate defining a Group template where the member Nodes act as ports.

As far as the nodes are concerned, you can make them as complicated as you like by customizing the Node template(s). However if you are going to have hundreds of them, I’d recommend keeping them as simple as you can.

To answer your last question: sure, it’s possible. You’ll need to customize the InputOutputGroupLayout that is in that sample.

thanks. this example has helped me understand things a bit better. although i will say it seems quite confusing to have a custom model structure (and corresponding transformation function) when showing the raw model would make things more clear.

however, having the order of ports automatically arranged for optimal link crossover prevention still doesn’t seem to be possible. your suggestion of customizing with a diagram subclass seems to imply that i would have to arrange the ports manually. i had assumed that since gojs is all about laying things out for you there would be a way to have the layout automatically move the ports to the optimal position so that the links to other nodes don’t crossover.

Yes, I had been assuming that your application had constraints that you understood and that would give you the preferred order of the nodes/ports on each side of a group.

By “links to other nodes” do you mean the links between groups? Or do you mean links between the nodes within a group?

If you mean the latter case, then a LayeredDigraphLayout will get you something like what you want, if you assign it to Group.layout.

If you mean the former case, it might be possible to use a custom LayeredDigraphLayout as the Diagram.layout which did the following operations:

  • treat all groups as nodes with a single port (or one input and one output)
  • do the regular LayeredDigraphLayout
  • arrange the nodes within each group so as to reduce link crossings
  • do the regular LayeredDigraphLayout again on the whole diagram, this time treating groups as nodes with ports at fixed locations (this is the standard behavior)

This is non-trivial for you to implement until you’ve become fairly familiar with customizing layouts that manipulate their LayoutNetwork to pretend to be operating on a different graph than the Diagram is actually showing.

our case is the latter. it doesn’t make sense to reduce a group to a single in and out when groups have multiple ins and outs to other groups. there’s no obvious choice to make in that reduction.

i’m guessing that when many links are drawn from a node to other nodes (with no ports) the layout can handle the ordering of nodes to reduce link crossover. why then, in the case when the links come from specific ports on a node, couldn’t the layout use this same functionality to determine the best ordering of ports?

What you are asking for is an unusual request. That’s not a feature of any layout that I know of. I outlined how I would implement that by customizing LayeredDigraphLayout.

But if you didn’t use discrete ports (whether nodes or not doesn’t matter) and instead had a single big port, then you can use fromSpot and/or toSpot to be a “Side…” Spot. See for example the diagrams on this page GoJS Link Connection Points on Nodes -- Northwoods Software that specify fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide. Then the connection points for the links are automatically sorted based on the relative direction of the nodes at the other ends of the links.

yes i understand now. something to try.

i have another idea: if i created individual group containers for each object’s left and right ports with a layered digraph layout and a vertical arrangement, would this automatically arrange the port order?

I’m not exactly sure what you are suggesting, but it is the case that you can use any of the Layouts that use LayoutNetworks to operate on abstract collections of vertexes and edges, without any corresponding real Nodes and Links.

Or maybe you are now thinking about what I suggested earlier – doing a LayeredDigraphLayout of the whole diagram, and then using that positioning to determine the order of the ports on each node. But that is why I suggested that to do that whole-diagram layout, each node would need to pretend to have only a single input and a single output port, so that the results would not be influenced by whatever ordering the ports had.

a layered digraph layout is designed to automatically put nodes in place to avoid link crossover. can i use this layout in a group of nodes that are restricted to a vertical stack of 1 column? given that these nodes link to other objects, will the layout arrange the ports to prevent crossover?

look at this screenshot. it is not difficult to see that re-arranging the ports would significantly reduce crossover. is there no automatic way of doing this?

i think what i’m realizing is that layouts do not optimize outside of their context. so having one digraph layout for a group will have no ability to optimize within that group for links that go outside of that group. is that correct?

If those really are separate ports, no, there’s no built-in way to rearrange the ports to reduce link crossings.

As I said, that is an unusual request. If you simply took out all ports from the node template(s) and used fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide, I think you’d be happy with the results as far as link crossings go. (I’m assuming links are going from left to right.) Besides the examples at GoJS Link Connection Points on Nodes -- Northwoods Software, there are: Sankey Diagram and Production Process Viewer and a few others.

Then I suppose you could reconnect the links to their individual ports by the vertical ordering of their end points.

thanks - i can see how it would be done this way.

while it may seem unusual, isn’t it a general optimization that would result in a better diagram? i can only assume no one has cared enough before to attempt it, though i’m sure it would have been used if the option existed.

Yes, but almost always when one uses separate ports, there is both a physical and a logical distinction between the ports that causes them not to be interchangeable.

For example, the ports of nodes representing the pins of integrated circuit chips can not be swapped. (This would be a special case of Page Not Found -- Northwoods Software)

Or imagine nodes that do arithmetic – you cannot swap the dividend and divisor.

Or the tables or results of a SQL Join: Data Flow Diagram.

So the common case that you are thinking of is already covered by having a single large port with fromSpot or toSpot set to some “Side” Spot.