Adding a node to a group after resizing the group

I want to add a node present in a palette into a group in the diagram.

The group already contains some nodes. So in order to add the node, I am resizing the group to create some space in it. When I drop the node into the empty space(of the group), it breaks the whole group. Now when I move the nodes, the nodes cross the boundaries of the group. The group does not resize along with the nodes.

Even if I simply resize the group, the movement of its children(already present in the group) breaks the group and they now escape its boundaries. How do I fix it?

I would think that the Group.layout should be responsible for positioning its member Nodes. If you are not using a Placeholder, the layout should also size its container. This may require cooperation with the Diagram.layout and with the ResizingTool. One example of such cooperation is demonstrated in the Swim Lanes sample.

Thank you for your suggestion. Using the sample, I have added the stayInGroup function to the dragComputation property of the internal nodes/groups. Now I am facing another issue.

I am setting the resizable propery of the groups as true. This is because I have to create some space to add new nodes/groups from the palette.

Whenever I resize the external group(to create some space) , and when I move the already present internal nodes, they stay within the group but the external group also moves along with the selected node… How do I restrict the movement of the external group when I move the internal nodes after resizing the group?

It is a bit difficult to understand. Please check out the screenshots below.

This is a group containing groups. The nodes have stayInGroup computation. The external group placeholder has some padding.

I have resized and expanded the external group in this figure.

Now when I select and move the internal left group to the bottom left of the external group, the external group also moves along with it until the right internal group encounters the boundaries of the external group.

I want the external group to be stationary while I am moving the internal nodes/groups.

Just found out another issue. After I expand the external group, If I decide to expand the internal group the group is now able to get out of the boundaries of the external group.

When I resize the internal group without resizing the external group, everything works fine. But after I resize the external group, the whole collection breaks.

This is when I resize the internal group without resizing the external group:

This is when I try to resize the internal group after I resize the external group:

How do I fix these two issues? These issues are critical as I have to drop new nodes in both internal and external groups.

Does the resizing of groups work the way that you like in the Swim Lanes sample?

The lane group in the swim lanes does not move when internal nodes are moved after their lane is resized. I want the same behavior. Also, the lanes do not contain nested groups so I can’t really say w.r.t. 2nd issue. I hope you understood these problems I am facing

The Swim Lanes sample does have nested groups, with a different Group.layout than what you want.

And clearly you need to customize the ResizingTool to limit how far groups (and nodes, if allowed) can shrink or grow.

I am modifying the resizingTool. But when I resize the external group and then resize the internal group, the external group is automatically moving to the right. I don’t know why. How do I stop that?

It’s hard for us to guess what might be wrong in your code. Are you sure that you want to use a Placeholder in your Group template(s)?

I am using the Placeholder for calculating computeMaxSize and computeMinSize of the resizing tool so as to restrict the shrinking of the groups.

This is the code for the groupTemplateMap.

    myDiagram.groupTemplateMap.add("siteType",
    goObj(go.Group, "Spot",new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), {
            layout: goObj(PoolLayout, {
                angle: 90,
                isOngoing: false
            })
        }, {
            selectionAdornmentTemplate: // adornment when a group is selected
                goObj(go.Adornment, "Auto",
                goObj(go.Shape, "Rectangle", {
                    fill: null,
                    stroke: "dodgerblue",
                    strokeWidth: 3
                }),
                goObj(go.Placeholder)
            ),
            toSpot: go.Spot.AllSides, // links coming into groups at any side
            toEndSegmentLength: 30,
            fromEndSegmentLength: 30,
            resizable: true,
            computesBoundsAfterDrag: true,  // needed to prevent recomputing Group.placeholder bounds too soon
            computesBoundsIncludingLinks: false,  // to reduce occurrences of links going briefly outside the lane
            handlesDragDropForMembers: true,  // don't need to define handlers on member Nodes and Links
        },
        goObj(go.Panel, "Auto",
            goObj(go.Shape, "Rectangle", {
                    name: "OBJSHAPE",
                    parameter1: 14,
                    fill: "transparent",
                    minSize: new go.Size(100, 100)
                },
                new go.Binding("desiredSize", "ds")),
            goObj(go.Placeholder, {
                padding: 30
            })
        ),
        goObj(go.TextBlock, {
                name: "GROUPTEXT",
                alignment: go.Spot.TopLeft,
                alignmentFocus: new go.Spot(0, 0, 4, 4),
                font: "Bold 20pt Sans-Serif"
            },
            new go.Binding("text", "lol"))
    ));
myDiagram.groupTemplateMap.add("serviceGroup",
    goObj(go.Group, "Spot",new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), {
            dragComputation: stayInGroup
        }, {
            layout: goObj(go.LayeredDigraphLayout, {
                angle: 90,
                isOngoing: false
            })
        }, {
            selectionAdornmentTemplate: // adornment when a group is selected
                goObj(go.Adornment, "Auto",
                goObj(go.Shape, "Rectangle", {
                    fill: null,
                    stroke: "dodgerblue",
                    strokeWidth: 3
                }),
                goObj(go.Placeholder)
            ),
            toSpot: go.Spot.AllSides, // links coming into groups at any side
            toEndSegmentLength: 30,
            fromEndSegmentLength: 30,
            resizable: true,
            computesBoundsAfterDrag: true,  // needed to prevent recomputing Group.placeholder bounds too soon
            computesBoundsIncludingLinks: false,  // to reduce occurrences of links going briefly outside the lane
            handlesDragDropForMembers: true,  // don't need to define handlers on member Nodes and Links
        },
        goObj(go.Panel, "Auto",
            goObj(go.Shape, "Rectangle", {
                    name: "OBJSHAPE",
                    parameter1: 14,
                    fill: "transparent",
                    minSize: new go.Size(100, 100)
                },
                new go.Binding("desiredSize", "ds")),
            goObj(go.Placeholder, {
                padding: 30
            })
        ),
        goObj(go.TextBlock, {
                name: "GROUPTEXT",
                alignment: go.Spot.TopLeft,
                alignmentFocus: new go.Spot(0, 0, 4, 4),
                font: "Bold 20pt Sans-Serif"
            },
            new go.Binding("text", "lol"))
    ));

I cannot understand why the external group is moving when I move the internal groups after I resize the external group. Please go through the below screenshots for more clarity.

This is the initial layout of the diagram.

This is after I resize the external group. Please note the below gap between the external group and internal groups.

Now when I move the right internal group to the top. The external group also moves a bit up automatically. You can note the difference in the bottom gap between the left internal group and the external group before and after I move the right group.

Similarly, when I resize the right group, the external group also moves to the right.

I am seeing the same behavior in the internal groups too, when I move the picture nodes after resizing the (internal) groups.
Why is this happening? How to fix this?

P.S. : This happens only after I resize the groups. When I move the nodes/groups without resizing their containingGroups, all works well.

I don’t know – I can only make wild guesses.

It seems to me that the Group’s Group.layout should be doing what you want, but it isn’t. What it should do will depend on whether or not you are using a Placeholder in the Group.

Have you set Group.locationSpot to go.Spot.Center? Maybe you shouldn’t.

As I said, I need the placeholder for the resizing tool prototype functions. I wouldn’t need the placeholder if there is another way to get the bounds of the area of the group. I have not set the locationSpot of the groups at all.

I am using two layouts in the group. The external group has a layout which is similar to the PoolLayout in the swim lane sample. The internal groups have a default LayeredDigraphLayout. The isOngoing property is set to false

At the time a Group.layout runs, or at the time the ResizingTool runs, it will know the size of all of its members, including of any nested Groups. Layouts normally just move its member nodes to where it wants them to be. But if your Group template does not have a Placeholder, you can adjust the size of the Group’s Shape (or whatever you are using as a border around the group’s member parts) and the Group’s position to suit your needs.

You can always call Diagram.computePartsBounds to figure out what area is occupied by the non-links in any collection of Parts. That’s basically what the Placeholder does when it’s trying to figure out how big it should be, except there are a few more options, as controlled by properties on the Group.

Thank you for suggesting Diagram.computePartsBounds. I have removed the placeholder and have set the size of the external group in my layout override. Everything works fine now.

I have another question, how to set the padding for the memberParts area? Using placeholder, it was done by simply setting the padding property.The padding property sets the padding for the whole group, including the borders. I don’t want the padding for the whole group, I want the padding for the area of its nodes.

If you aren’t using a Placeholder any more, then you can decide how to automatically resize some GraphObjects to make them appear as if they surround the member Parts.

You know about Diagram.computePartsBounds and Rect.addMargin. But I have no idea of how you want to implement a border or frame around a group’s members.

I didn’t mean to implement another border around the members. Apologies if there was a misunderstanding.

When I set the padding property for the whole group, even the border is getting padded.

How do I resize the group programmatically. The diagram.resizeTool is returning null. Also, I thought of setting the padding using Rect.grow function. Could this be useful in setting top and left padding. If so,How can I access and modify the shape of the graph object?

You might want to do what the Planogram sample does: Planogram

I did not understand how the planogram solves my issue. In my diagram, the left and top border of the internal group overlaps the left and top border of the external group. I want to create a padding between these two groups so that it would be clear what is what.

Then I would think the outer Group.layout would want to call Node.move on its one member node (which happens to be a nested Group) to position it where you’d like it to be.

Thank you. I somehow got it working well and good. I have one final question. This is related to resizing the group.

This is the layout of my initial group:

Now I have expanded the group:

Let us say I have moved the left internal group to the top like this:

Now if I shrink the group back, the left internal group moves automatically can now escape the bounds of the external group like this:

How do I ensure that the internal groups/nodes stay within the group while it is being shrunk?

My resizing tool has the following computeMinSize code:

function computePlaceholderSize(theDiagram,group) {
    var minWidth = MINLENGTH;
    var minHeight = MINBREADTH;
    var sz;
    if(group.containingGroup == null){
        //this is the external group
        sz = theDiagram.computePartsBounds(group.memberParts);
        console.log('group coordinates: '+group.actualBounds.x+':'+group.actualBounds.y)
        console.log('node area coordinates: '+sz.x+':'+sz.y)
    }else{
        //this is the internal group
         sz = group.actualBounds;
    }
    
    return new go.Size(Math.max(minWidth, sz.width), Math.max(minHeight, sz.height));
}

function GroupResizingTool() {
    go.ResizingTool.call(this);
}
go.Diagram.inherit(GroupResizingTool, go.ResizingTool);

GroupResizingTool.prototype.computeMinSize = function() {
    var group = this.adornedObject.part;
    console.log(group.data)
    var msz = computeMinPlaceholderSize(); // get the minimum size
    var sz = computePlaceholderSize(this.diagram,group);
    msz.width = Math.max(msz.width, sz.width);
    msz.height = Math.max(msz.height, sz.height);
    return msz;
}

Yes, just limiting the size to be big enough is insufficient – you also need to limit position by overriding ResizingTool.computeResize or ResizingTool.resize. Remember that the returned Rect is in local coordinates, not document coordinates.