Below is the layout code
This is the group template
const go = this.graphComponent.goObject;
const $ = go.GraphObject.make;
const updateGroupLabel = g => {
const tb = g.findObject("LABEL");
if (!tb) return;
tb.text =
(g.isSubGraphExpanded ? "-" : "+") +
(g.part.data?.metaData?.nodeCount ||
g.part.data?.metaData?.nodeCount === 0
? g.part.data.metaData.nodeCount
: g.memberParts.filter(m => m instanceof go.Node).count);
};
const customGroup = $(
go.Group,
"Vertical",
{
locationSpot: go.Spot.Center,
layout: $(go.LayeredDigraphLayout, {
direction: 90,
packOption: go.LayeredDigraphLayout.PackStraighten,
}),
subGraphExpandedChanged: updateGroupLabel,
memberAdded: updateGroupLabel,
memberRemoved: updateGroupLabel,
selectable: false,
},
new go.Binding("isSubGraphExpanded", "", function(data) {
if (data.disabled) {
return false;
}
return data.isSubGraphExpanded;
}).makeTwoWay(function(expandState, data, model) {
model.setDataProperty(data, "isSubGraphExpanded", expandState);
}), // remember expansion state
$(
go.Panel,
"Auto",
{
click: (e, g) => {
if ((g.part as go.Group).data.disabled !== true) {
if ((g.part as go.Group).isSubGraphExpanded) {
e.diagram.commandHandler.collapseSubGraph(g.part as go.Group);
} else {
e.diagram.commandHandler.expandSubGraph(g.part as go.Group);
}
}
},
},
new go.Binding("cursor", "disabled", function(v) {
return v ? null : "pointer";
}),
new go.Binding("toolTip", "", (data: any) => {
return data?.disabled
? this.createToolTipTemplate(data?.metaData, $)
: null;
}),
$(
go.Shape,
"RoundedRectangle",
{
fill: "#FFF",
strokeWidth: 1,
},
new go.Binding("stroke", "disabled", function(v) {
return v ? "#B4B3BD" : "#D6E2FA";
})
),
$(
go.TextBlock,
{
name: "LABEL",
margin: new go.Margin(6, 8, 6, 8),
font: "bold 12pt open sans",
},
new go.Binding("stroke", "disabled", function(v) {
return v ? "#B4B3BD" : "#3470E4";
})
)
),
$(
go.Panel,
"Vertical",
new go.Binding("visible", "isSubGraphExpanded").ofObject(),
$(
go.Shape,
"LineV",
{ width: 2, height: 7 },
new go.Binding(
"stroke",
"metaData",
metaData => metaData?.strokeColor
)
),
$(
go.Shape,
{
toArrow: "Triangle",
angle: 90,
stroke: null,
strokeWidth: 0,
},
new go.Binding("fill", "metaData", metaData => metaData?.strokeColor)
),
$(
go.Panel,
"Auto",
$(go.Shape, "RoundedRectangle", {
fill: "white",
strokeWidth: 1.5,
strokeDashArray: [2, 2],
}),
$(go.Panel, "Vertical", $(go.Placeholder, { padding: 10 }))
)
)
);
const templateMap = new go.Map<string, go.Group>();
templateMap.add("additional_node_group", customGroup);
templateMap.add("", this.graphComponent.graphDiagram.groupTemplate);
this.graphComponent.graphDiagram.groupTemplateMap = templateMap;
To expand/collapase all groups I use this code
this.graphComponent?.graphDiagram.commit(d => {
d?.model?.nodeDataArray?.forEach(nodeData => {
const nodeObject = d.findNodeForKey(nodeData?.id);
if (
nodeObject &&
nodeObject?.part.data.isGroup &&
nodeObject?.part.data.disabled !== true
) {
if (this.expandAll?.value) {
(nodeObject.part as go.Group).expandSubGraph();
} else {
(nodeObject.part as go.Group).collapseSubGraph();
}
}
});
});