Implementation suggestions for complex swimlane diagram

Hello @walter,
I have a new requirement which is that the labels of the informationTypes (“Node 1 - TextPanel”, “Node 2 - TextPanel” …) should always be visible if the user scrolls the diagram horizontally.
The reason is that there will be many process nodes (the nodes at the top) and if the user scrolls far to the right, he should still be able to see the informationType Labels.
Basically we need a similar functionality to the “Freeze column” functionality in Excel.
Do you have any suggestion what goJS feature I could for this requirement?

P.S: I haven’t started implementing yet so I could still change the concept if necessary.

What did you implement to address the original topic?

Nothing yet, I was just about to start.

Ah, so that was what you meant. OK, I suggest that you implement the things that should not scroll as one or more separate Parts: GoJS Legends and Titles -- Northwoods Software

1 Like

Hello @walter,

I have implemented the Process nodes. I have also tried your suggestion with StaticParts.
The result is a strange scrolling behavior. I have reproduced it here:
codepen
Here is the code of the example:

  function init() {
    var $ = go.GraphObject.make;
    myDiagram = $(go.Diagram, "myDiagramDiv",
                  {initialContentAlignment: go.Spot.Center,"undoManager.isEnabled": true});

    myDiagram.nodeTemplate =
      $(go.Node, "Auto", 
        $(go.Shape, "RoundedRectangle", { fill: "lightblue" }),
        $(go.TextBlock, { margin: 8 }, new go.Binding("text", "text"))
      );
    
    myDiagram.addDiagramListener("ViewportBoundsChanged", (e) => 
    {
      let dia = e.diagram;
      let node = dia.findNodeForKey(1);
      node.location = dia.transformViewToDoc(new go.Point(10, 150)); // try different x values: 0, 5, 10 
    });
    
    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text:"Alpha", color: "lightblue" },
      { key: 2, text:"Beta", color: "orange" },
      { key: 3, text:"Gamma", color: "lightgreen" },
      { key: 4, text:"Delta", color: "pink" }
    ]);

  }
init();

If you move the nodes to the left, then there is a delay. It also depends on the zoom and location of nodes.
Also if you change the x value of the static part from 10 to 0 or 5 the behaviour becomes even more strange.

The StaticParts example uses a go.Part instead of a go.Node. But I need to use nodes for the informationType items and their horizontal lines.

Any ideas how this can be solved?

It’s OK if it’s a Node rather than a Part.

I suspect that the reason is at least partially due to the chosen Node being part of the document, thereby always contributing to the computation of the Diagram.documentBounds.

If you use a separate template or bind Part.isInDocumentBounds so that the value is false for your chosen Node, I think the behavior would be better.

Note that the example in GoJS Legends and Titles -- Northwoods Software has the chose Part in the “Grid” Layer, which both avoids having it be in the document bounds and also avoids recording its changes to the UndoManager.

Hello @walter,

thanks. Both suggestions solve the scrolling problems.

node.layerName = "Grid";

OR

node.isInDocumentBounds = false; 

Setting the layerName to “Grid” has the effect that the “static” node will be behind all other nodes, no matter which zOrder is set.
So I will use isInDocumentBounds and set the layerName to “Foreground” or set zOrder.

I have updated the example here: link
Which brings me to the next two questions about scrolling:

  1. When the most left node comes into view, I cannot move the nodes further to the right. The pink panel will be without opacity later and will hide the nodes behind it. So I need to move the nodes to the right until all nodes become visible.

  2. The horizontal black line is a node, which will have ports later. I want to limit the scroll position, so that I can avoid the gap shown in the image below. That means the x location of the line should always be equal or smaller than the width of the pink panel. (but of course without modifying the x location itself, because it is related to the other nodes). I want to limit the scroll position.

You can control where the user can scroll. Have you read GoJS Coordinate Systems-- Northwoods Software and seen Scroll Modes GoJS Sample ?

Thanks Walter,

I have solved the first point by setting the line x-location and moving the process nodes to the right.
I solved the second point by handling the positionComputation event. Thank you.

The next step is to group multiple static parts. When I add multiple static nodes to a group, the group is created around the nodes. When I try to set the group location in my code, then the group is moved, but the nodes remain on their locations. You can see this behavior here: link. When you move the node 2 or 3 the group is redrawn again around the nodes 2 and 3.

I have also tried, to set the “Vertical” type and also tried to add a GridLayout to the group. But the nodes are still not placed into the group.
The Group Templates example here also sets the “Vertical” type on the group, but the nodes within the group are aligned horizontally.

I would like to define a location and a width for the group. Then all nodes assigned to the group should be aligned vertically within the group. Like it is done in a vertical panel, without the need to calculate the location of each element. How can I do this?

image
In this image, both nodes are aligned vertically and the height of the nodes can change, so the second node should always start below the first node.

If you want to move a Group, call Group.move.

For the second scenario, is it sufficient to just set Group.layout to a GridLayout whose GridLayout.wrappingColumn is set to 1?

Hello Walter,

Group.move did the trick .
(Setting group location like described on static parts does not move the content of the group.)

I am quite close to what I want at the end, but now I have two questions about links/ports:
Question 1:
I have two types of ports.

  • The ports on the process nodes (Type A)
  • The ports on the bottom lanes (Type B)

I want to allow only connections from A to B or from B to A.
But not from A to A nor B to B.

I have found an example (Grafcet Diagrams) which uses categories and overrides the linking tool to define which category the new link gets.

But I think for such a simple limitation, there is another solution. Something which can be “hardcoded” in the model or the template. Is there an easier solution?

Question 2:
A process node contains a table where each column (see image below) can have multiple links to the bottom lanes or the other way.
image
If there are only links from A to B (red) or only links from B to A (green) then the link and port should be located in the middle of the column.
But if there are green and red links (like in column 4) then the links and ports should be located at about 33% and 66% of the columns width.
What is the best way to achieve that?

(btw. Column 2 has two downward links, because there are two filled circles at the first and last lane.)

Thank you in advance

#1 The default valid linking behavior, GoJS Validation -- Northwoods Software, disallows reflexive links.

#2 Set fromSpot and toSpot to go.Spot.BottomSide for port A and go.Spot.TopSide for port B.

Hello Walter,

#1 solved, thank you.

#2 your suggestion worked, but I realised that i need to create my own link class, in order to be able to define the link point.

Based on this example I have created my own link class which extends go.Link and I have overwritten the getLinkPoint function. It works with a simple node. I use the port parameter to determine the rectangle and calculate the link points.

I have added a table, bound an itemArray and created a TableColumn template. I have set the link-properties on the TableColumn. When I create a link to or from a column the column is highlighted.


codepen link

The problem now is that no matter to or from which column I drag the link, rectangle defined by the parameter port in the function getLinkPoint is always the most right column. The result is that the links are always “connected” to the most right column.

How can I get the correct column in the getLinkPoint (the column where I have dragged the link with the mouse)?

It sounds as if the link really is connecting with the port on the right. That’s odd. Can you confirm that (for that node) there are three ports? If you select that Node:

myDiagram.selection.first().ports.count

If that indeed evaluates to 3, have you set GraphLinksModel.linkFromPortIdProperty and GraphLinksModel.linkToPortIdProperty?

no there is only one port. That´s strange.

Here is the table definition part from the above codepen link:

$(go.Panel, "Table", {
        stretch: go.GraphObject.Fill,
        name: "table"
    },
    new go.Binding("itemArray"), {
        itemTemplate: $(go.Panel, "TableColumn", {
            name: "column",
            portId: "",
            fromLinkableDuplicates: true,
            toLinkableDuplicates: true,
            fromLinkable: true,
            toLinkable: true
        })
// further parts here ...
    });

I have expected that if I have 3 columns I would get 3 ports, because the port is activated for the panel within the itemTemplate. Is this wrong?

Three elements have GraphObject.portId set to a string, but because you set them all to the same string, the ports do not have unique identifiers, so it’s ambiguous. I guess Node.port happens to get what you think of as the last one.

I have added a binding to portId, to make it unique within a node.

But now the parameter port in the overridden function getLinkPoint is always the node itself.

How do I know on which part (which column in my case) the link was dragged?

Have you set GraphLinksModel.linkFromPortIdProperty and GraphLinksModel.linkToPortIdProperty ?

Great, that was the reason. I thought it is only required when I want to write the data back into my model.

That´s what I wanted:
image

Thank you

A post was split to a new topic: Changing behavior of temporary link when drawing a new link