A Placeholder is used to make sure the Group naturally has at least the same bounds (position and size) as its collection of member Parts. I still cannot tell how you are using Groups, so I cannot say whether you should be using a Placeholder or not.
Does this code do something like what you want?
If so, you could programmatically change the size of a “group” by setting its data.size
property. (Within a transaction of course.)
<!DOCTYPE html>
<html>
<head>
<title>Simple Group Resizing</title>
<!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
This sample uses a Group template that does not use a Placeholder, but allows the user
to resize the group. Resizing of a group will not allow the group to resize smaller than its members.
Moving member nodes is limited to stay within the group.
<script src="../latest/release/go.js"></script>
<script id="code">
const $ = go.GraphObject.make;
const GroupMargin = new go.Margin(5);
myDiagram =
new go.Diagram("myDiagramDiv",
{
"resizingTool.computeMinSize": function () { // method override
const group = this.adornedObject.part;
const membnds = group.diagram.computePartsBounds(group.memberParts);
membnds.addMargin(GroupMargin);
membnds.unionPoint(group.location);
return membnds.size;
},
"undoManager.isEnabled": true
});
// this is a Part.dragComputation function for limiting where a Node may be dragged
function stayInGroup(part, pt, gridpt) {
// don't constrain top-level nodes
const grp = part.containingGroup;
if (grp === null) return pt;
// try to stay within the background Shape of the Group
const back = grp.resizeObject;
if (back === null) return pt;
// allow dragging a Node out of a Group if the Shift key is down
//if (part.diagram.lastInput.shift) return pt;
const p1 = back.getDocumentPoint(go.Spot.TopLeft);
const p2 = back.getDocumentPoint(go.Spot.BottomRight);
const b = part.actualBounds;
const loc = part.location;
// no placeholder -- just assume some Margin
const m = GroupMargin;
// now limit the location appropriately
const x = Math.max(p1.x + m.left, Math.min(pt.x, p2.x - m.right - b.width - 1)) + (loc.x - b.x);
const y = Math.max(p1.y + m.top, Math.min(pt.y, p2.y - m.bottom - b.height - 1)) + (loc.y - b.y);
return new go.Point(x, y);
}
myDiagram.nodeTemplate =
$(go.Node,
{ dragComputation: stayInGroup, locationSpot: go.Spot.Center },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.TextBlock, new go.Binding("text", "key"))
);
myDiagram.groupTemplate =
$(go.Group, "Vertical",
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
selectionObjectName: "SHAPE",
resizable: true, resizeObjectName: "SHAPE",
computesBoundsAfterDrag: true
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.TextBlock, { font: "bold 11pt sans-serif" },
new go.Binding("text", "key")),
$(go.Shape, { name: "SHAPE", fill: "whitesmoke" },
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify))
);
myDiagram.model = new go.GraphLinksModel(
[
{ key: "Alpha", loc: "65 -35" },
{ key: "Beta", group: "Epsilon", loc: "90 40" },
{ key: "Gamma", group: "Epsilon", loc: "125 85" },
{ key: "Delta", loc: "113 153" },
{ key: "Epsilon", isGroup: true, loc: "115 60" }
], [
{ from: "Alpha", to: "Beta" },
{ from: "Beta", to: "Gamma" },
{ from: "Gamma", to: "Delta" }
]);
myDiagram.select(myDiagram.findTopLevelGroups().first());
</script>
</body>
</html>