I’m trying to do some viewport manipulation after a SubGraph is expanded, but I’m having a lot of trouble because the redraw hasn’t happened when the SubGraphExpanded event fires. I can move my listener to LayoutChanged or something similar, but then I lose all the information from the DiagramEvent.

Is my only option to save off the subject and then consume it in a LayoutChanged listener I attach/detach in the expanded event?

E.g. I want to do something like this:

      SubGraphExpanded: (e: go.DiagramEvent) => {
        const nodes = e.subject as go.List<go.Group>;
        const zoomRect = new go.Rect();
        nodes.each((node) => zoomRect.unionRect(node.actualBounds));

I’m thinking I’m also going to have to union that with the viewport to get it to zoom in/out as well.

The “SubGraphExpanded” DiagramEvent is raised towards the end of the CommandHandler.expandSubGraph command, but still before the transaction has been committed. At that time no layouts have been performed, so the Group(s) are unlikely to have their final size and position (actualBounds).

FYI, the Group.subGraphExpandedChanged event is raised even earlier, during the expansion process.

I suggest you do something like this instead:

      SubGraphExpanded: (e: go.DiagramEvent) => {
        const nodes = e.subject as go.List<go.Group>;
        setTimeout(() => e.diagram.scrollToRect(e.diagram.computePartsBounds(nodes)));

Or maybe:

SubGraphExpanded: e => {
  setTimeout(() => {
    const group = (e.subject as go.List(<go.Group>)).first();

Hmm I was specifying a short timeout and having some weird issues, don’t know why I never thought to check a timeout without a duration. Thanks

I have a similar case (in a BPMN editor like example): I need to turn off layout.isOngoing after a Lane (in a Pool) is expanded and layout is done. That for initial generated models (that do not have locations and points. ) that depend on auto-layout. I’m not sure if it is according to GoJS best practices or not but I do this on swimLanesGroupTemplate:

           subGraphExpandedChanged: function (grp) {
                if (grp.diagram === null) return;
                if (grp.diagram.undoManager.isUndoingRedoing) return;

                const shp = grp.resizeObject;

                if (grp.isSubGraphExpanded) {
                    // Turn off layout.isOngoing if was generated
                    if (!grp.layout.isValidLayout && grp.layout.isOngoing) {
                        const listener = function () {
                            if (grp.layout.isValidLayout) {
                                grp.layout.isOngoing = false;
                                grp.diagram.removeDiagramListener('LayoutCompleted', listener);
                        grp.diagram.addDiagramListener('LayoutCompleted', listener);

And it seems to work perfectly - the diagram can be edited freely by the user without Layout intervention. I don’t like timeouts. Ideally if there are some events to be used. What I noticed is that GoJs layouts or parts don’t have independent events, I need to listen on the whole diagram.

Hmm, but I just found the thread Layout invalidated when node change size in SwimmingLane - #6 by walter
And following idea seems way better for my case:

When you want to force all of the layouts to be performed, one calls Diagram.layoutDiagram(true).
That way you can leave the Group.layout with Layout.isInitial and Layout.isOngoing set to false.