BPMN subprocess expand problem

As you can see in the image, when the subprocess is expanded, the objects get into each other

how do i solve this problem?

The BPMN sample is mostly designed so that users have to manually position each node.

In the case of an expanded Group, or any Node that has changed size, it is normal in GoJS to perform the layout again. However, the Group.layout for the lane, a LayeredDigraphLayout, has its Layout.isOngoing property set to false. That is preventing the automatic layout from being performed after the group changes size.

If you want to, you could offer the user a command that would explicitly invalidate that lane’s layout, by setting Layout.isValidLayout to false and then calling Diagram.layoutDiagram.

Or you could do that in a GoJS Events -- Northwoods Software listener.

Please read GoJS Layouts -- Northwoods Software for more explanation about layout invalidation.

I guess I couldn’t explain it exactly.

Can I make objects like SubProcess rise above all links and objects when expanding?
Any examples as code?

Did you want groups to be in front of regular nodes? OK, but what if the nearby nodes are themselves groups (subprocesses)?

The nearby group may be above the other group.
It is enough if I clear the visual mess


Like that

Try modifying the Group.subGraphExpandedChanged event handler to select the Group after it has been expanded.

        subGraphExpandedChanged: function (grp: go.Group) {
          if (grp.diagram === null) return;
          if (grp.diagram.undoManager.isUndoingRedoing) return;
          if (grp.isSubGraphExpanded) {
            // selecting the group will put it in the "Foreground" Layer
            grp.diagram.select(grp);
          }
        },

[EDITED]

there was no change. Unfortunately the problem persists :(

function updateCrossLaneLinks(group) {
   group.findExternalLinksConnected().each(function (l) {
       l.visible = (l.fromNode.isVisible() && l.toNode.isVisible());
   });
}

var subProcessGroupTemplate = GO(go.Group, "Spot",
                {
                    locationSpot: go.Spot.Center,
                    locationObjectName: "PH",
                    memberValidation: function (group, part) {
                        return !(part instanceof go.Group) ||
                            (part.category !== 'Pool' && part.category !== 'Lane');
                    },
                    mouseDrop: function (e, grp) {
                        if (!(grp instanceof go.Group) || grp.diagram === null)
                            return;
                        var ok = grp.addMembers(grp.diagram.selection, true);
                        if (!ok)
                            grp.diagram.currentTool.doCancel();
                    },
                    subGraphExpandedChanged: function (grp) {
                        if (grp.diagram === null) return;
                        if (grp.diagram.undoManager.isUndoingRedoing) return;
                        const shp = grp.resizeObject;
                        if (grp.isSubGraphExpanded) {
                            shp.height = grp['_savedBreadth'];
                            // selecting the group will put it in the "Foreground" Layer
                            grp.diagram.select(grp);
                        } else {
                            grp['_savedBreadth'] = shp.height;
                            shp.height = NaN;
                        }
                        updateCrossLaneLinks(grp);
                    },
                    contextMenu: activityNodeMenu,
                    itemTemplate: boundaryEventItemTemplate,
                    selectionAdorned: false
                },
                new go.Binding("itemArray", "boundaryEventArray"),
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                new go.Binding("isSubGraphExpanded", "isExpanded").makeTwoWay(),
                GO(go.Panel, "Auto",
                    GO(go.Shape, "RoundedRectangle",
                        {
                            name: "PH", fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
                            minSize: new go.Size(SubprocessNodeWidth, SubprocessNodeHeight),
                            portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
                            fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
                        },
                        new go.Binding("stroke", "isSelected", function (sel) {
                            if (sel) return "dodgerblue"; else return "black";
                        }).ofObject(""),
                        new go.Binding("fill", "isSelected", function (sel) {
                            if (sel) return "#f0f8ff"; else return "white";
                        }).ofObject(""),
                        new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
                    ),
                    GO(go.Panel, "Vertical",
                        { defaultAlignment: go.Spot.Left },
                        GO(go.TextBlock,
                            { margin: 3, editable: false },
                            new go.Binding("text", "", function (val, node) {
                                var name = "";
                                if (val && val.externalData && val.externalData.Name !== undefined && val.externalData.Name !== null) {
                                    name = val.externalData.Name;
                                }
                                return name == "" ? val.text : name;
                            }).makeTwoWay(),
                            new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
                        GO(go.Placeholder,
                            { padding: new go.Margin(5, 5) }),
                        makeMarkerPanel(true, 1)
                    )
                )
            );

Oops, I copied from the wrong place. I have updated my code, above.

In that Group template you also need to uncomment:

      new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),

Yes the items appeared on the objects but the child items disappeared

My Code:

var subProcessGroupTemplate = GO(go.Group, "Spot",
                {
                    locationSpot: go.Spot.Center,
                    locationObjectName: "PH",
                    memberValidation: function (group, part) {
                        return !(part instanceof go.Group) ||
                            (part.category !== 'Pool' && part.category !== 'Lane');
                    },
                    mouseDrop: function (e, grp) {
                        if (!(grp instanceof go.Group) || grp.diagram === null)
                            return;
                        var ok = grp.addMembers(grp.diagram.selection, true);
                        if (!ok)
                            grp.diagram.currentTool.doCancel();
                    },
                    subGraphExpandedChanged: function (grp) {
                        if (grp.diagram === null) return;
                        if (grp.diagram.undoManager.isUndoingRedoing) return;
                        if (grp.isSubGraphExpanded) {
                            grp.diagram.select(grp);
                        }
                    },
                    contextMenu: activityNodeMenu,
                    itemTemplate: boundaryEventItemTemplate,
                    selectionAdorned: false
                },
				new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
                new go.Binding("itemArray", "boundaryEventArray"),
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                new go.Binding("isSubGraphExpanded", "isExpanded").makeTwoWay(),
                GO(go.Panel, "Auto",
                    GO(go.Shape, "RoundedRectangle",
                        {
                            name: "PH", fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
                            minSize: new go.Size(SubprocessNodeWidth, SubprocessNodeHeight),
                            portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
                            fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
                        },
                        new go.Binding("stroke", "isSelected", function (sel) {
                            if (sel) return "dodgerblue"; else return "black";
                        }).ofObject(""),
                        new go.Binding("fill", "isSelected", function (sel) {
                            if (sel) return "#f0f8ff"; else return "white";
                        }).ofObject(""),
                        new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
                    ),
                    GO(go.Panel, "Vertical",
                        { defaultAlignment: go.Spot.Left },
                        GO(go.TextBlock,
                            { margin: 3, editable: false },
                            new go.Binding("text", "", function (val, node) {
                                var name = "";
                                if (val && val.externalData && val.externalData.Name !== undefined && val.externalData.Name !== null) {
                                    name = val.externalData.Name;
                                }
                                return name == "" ? val.text : name;
                            }).makeTwoWay(),
                            new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
                        GO(go.Placeholder,
                            { padding: new go.Margin(5, 5) }),
                        makeMarkerPanel(true, 1)
                    )
                )
            );

OK, remove that Binding of “isSubGraphExpanded”, and make the subGraphExpandedChanged event handler change the layer of all of the groups members, too.

subGraphExpandedChanged: function(grp) {
  var lay = grp.isSubGraphExpanded ? "Foreground" : "";
  grp.layerName = lay;
  grp.findSubGraphParts().each(function(m) { m.layerName = lay; });
}

I haven’t tested this, but I think it’s more along the lines of what you want.

I added the codes you said, but such problems occur

My Code :

var subProcessGroupTemplate = GO(go.Group, "Spot",
                {
                    locationSpot: go.Spot.Center,
                    locationObjectName: "PH",
                    isSubGraphExpanded: false,
                    memberValidation: function (group, part) {
                        return !(part instanceof go.Group) ||
                            (part.category !== 'Pool' && part.category !== 'Lane');
                    },
                    mouseDrop: function (e, grp) {
                        if (!(grp instanceof go.Group) || grp.diagram === null)
                            return;
                        var ok = grp.addMembers(grp.diagram.selection, true);
                        if (!ok)
                            grp.diagram.currentTool.doCancel();
                    },
                    subGraphExpandedChanged: function (grp) {
                        var lay = grp.isSubGraphExpanded ? "Foreground" : "";
                        grp.layerName = lay;
                        grp.findSubGraphParts().each(function (m) { m.layerName = lay; });
                    },
                    contextMenu: activityNodeMenu,
                    itemTemplate: boundaryEventItemTemplate,
                    selectionAdorned: false
                },
                new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
                new go.Binding("itemArray", "boundaryEventArray"),
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                GO(go.Panel, "Auto",
                    GO(go.Shape, "RoundedRectangle",
                        {
                            name: "PH", fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
                            minSize: new go.Size(SubprocessNodeWidth, SubprocessNodeHeight),
                            portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
                            fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
                        },
                        new go.Binding("stroke", "isSelected", function (sel) {
                            if (sel) return "dodgerblue"; else return "black";
                        }).ofObject(""),
                        new go.Binding("fill", "isSelected", function (sel) {
                            if (sel) return "#f0f8ff"; else return "white";
                        }).ofObject(""),
                        new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
                    ),
                    GO(go.Panel, "Vertical",
                        { defaultAlignment: go.Spot.Left },
                        GO(go.TextBlock,
                            { margin: 3, editable: false },
                            new go.Binding("text", "", function (val, node) {
                                var name = "";
                                if (val && val.externalData && val.externalData.Name !== undefined && val.externalData.Name !== null) {
                                    name = val.externalData.Name;
                                }
                                return name == "" ? val.text : name;
                            }).makeTwoWay(),
                            new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
                        GO(go.Placeholder,
                            { padding: new go.Margin(5, 5) }),
                        makeMarkerPanel(true, 1)
                    )
                )
            );

Could you please be more specific about what the problem is?
If you want the links to be shown, I suggest you create a separate Layer just for the Links, and set Link.layerName to that layer name in all of the link templates.
https://gojs.net/latest/intro/layers.html

Can you share a sample code? About how to do please

OK, I have added a function that makes sure all of the member Parts are moved into the same Layer together, and made sure that function is called when a group’s selection state changes or when groups are expanded or when nodes or links are added to groups. Look for the assignGroupLayer function in the updated BPMNScript.ts file.

NOTE: I also removed the Bindings on “layerName” depending on “isSelected” from the regular Node templates.

Here’s the updated subProcessGroupTemplate and the assignGroupLayer function:

  function assignGroupLayer(grp: go.Part): void {
    if (!(grp instanceof go.Group)) return;
    var lay = grp.isSelected ? "Foreground" : "";
    grp.layerName = lay;
    grp.findSubGraphParts().each(function(m: go.Part) { m.layerName = lay; });
  }

  const subProcessGroupTemplate =
    $(go.Group, 'Spot',
      {
        locationSpot: go.Spot.Center,
        locationObjectName: 'PH',
        // locationSpot: go.Spot.Center,
        isSubGraphExpanded: false,
        subGraphExpandedChanged: function(grp: go.Group) {
          if (grp.isSubGraphExpanded) grp.isSelected = true;
          assignGroupLayer(grp);
        },
        selectionChanged: assignGroupLayer,
        computesBoundsAfterDrag: true,
        memberValidation: function (group: go.Group, part: go.Part) {
          return !(part instanceof go.Group) ||
                 (part.category !== 'Pool' && part.category !== 'Lane');
        },
        mouseDrop: function (e: go.InputEvent, grp: go.GraphObject) {
          if (e.shift || !(grp instanceof go.Group) || grp.diagram === null) return;
          const ok = grp.addMembers(grp.diagram.selection, true);
          if (!ok) grp.diagram.currentTool.doCancel();
          else assignGroupLayer(grp);
        },
        contextMenu: activityNodeMenu,
        itemTemplate: boundaryEventItemTemplate,
        avoidable: false
      },
      new go.Binding('itemArray', 'boundaryEventArray'),
      new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
      $(go.Panel, 'Auto',
        $(go.Shape, 'RoundedRectangle',
          {
            name: 'PH', fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
            minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
            portId: '', fromLinkable: true, toLinkable: true, cursor: 'pointer',
            fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
          },
          new go.Binding('strokeWidth', 'isCall', function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
        ),
        $(go.Panel, 'Vertical',
          { defaultAlignment: go.Spot.Left },
          $(go.TextBlock,  // label
            { margin: 3, editable: true },
            new go.Binding('text', 'text').makeTwoWay(),
            new go.Binding('alignment', 'isSubGraphExpanded', function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
          // create a placeholder to represent the area where the contents of the group are
          $(go.Panel, "Auto",
            $(go.Shape, { opacity: 0.0 }),
            $(go.Placeholder,
              { padding: new go.Margin(5, 5) })
          ),  // end nested Auto Panel
          makeMarkerPanel(true, 1)  // sub-process,  loop, parallel, sequential, ad doc and compensation markers
        )  // end Vertical Panel
      )  // end border Panel
    );  // end Group

and the updated Diagram initialization:

  myDiagram =
    $(go.Diagram, 'myDiagramDiv',
      {
        nodeTemplateMap: nodeTemplateMap,
        linkTemplateMap: linkTemplateMap,
        groupTemplateMap: groupTemplateMap,

        commandHandler: new DrawCommandHandler(),  // defined in DrawCommandHandler.js
        // default to having arrow keys move selected nodes
        'commandHandler.arrowKeyBehavior': 'move',

        mouseDrop: function (e: go.InputEvent) {
          // when the selection is dropped in the diagram's background,
          // make sure the selected Parts no longer belong to any Group
          const ok = myDiagram.commandHandler.addTopLevelParts(myDiagram.selection, true);
          if (!ok) myDiagram.currentTool.doCancel();
        },
        resizingTool: new LaneResizingTool(),
        linkingTool: new BPMNLinkingTool(), // defined in BPMNClasses.js
        relinkingTool: new BPMNRelinkingTool(), // defined in BPMNClasses.js
        'SelectionMoved': relayoutDiagram,  // defined below
        'SelectionCopied': relayoutDiagram,
        "LinkDrawn": function(e) { assignGroupLayer(e.subject.containingGroup); },
        "LinkRelinked": function(e) { assignGroupLayer(e.subject.containingGroup); }
      });

and look for and delete the Bindings that look like:

new go.Binding("layerName", "isSelected", ...)

Thank you very much. It worked