@walter - We are trying the example code you supplied, but the bounds of the group being accessed in shiftNodes:
var b = part.actualBounds;
That’s the bounds before the group is expanded. We really need the bound after it’s expanded for this to work. Any idea why we’re getting the bounds before?
Here’s our code:
Group template:
$(
Group,
"Auto",
{
mouseEnter: onMouseEnter,
mouseLeave: onMouseLeave,
subGraphExpandedChanged: function (grp: Group) {
if (!grp.isSubGraphExpanded) return;
shiftNodes(grp);
},
},
{ deletable: false },
new Binding("isSubGraphExpanded", "expanded").makeTwoWay(),
// This ensures collapsed groups are rendered in front of links
// but expanded groups are rendered behind links
new Binding("layerName", "isSubGraphExpanded", pickLayer).ofObject(),
{ layout: $(Layout), isSubGraphExpanded: false },
$(
Shape,
"RoundedRectangle",
new Binding("fill", "labelKey", (labelKey) => {
const { backgroundColor } = labelConfigFromLabelKey(
labelKey,
labelData
);
return backgroundColor;
}),
{
fill: White.L000,
stroke: Black.L500,
strokeWidth: 1,
}
),
$(
Panel,
"Table",
{ margin: 0.5, padding: 12 }, // avoid overlapping border with table contents
$(RowColumnDefinition, { row: 0, background: null }), // header is white
$("SubGraphExpanderButton", { row: 0, column: 0, margin: 3, padding: 3 }),
$(
TextBlock, // title is centered in header
{
row: 0,
column: 1,
font: "bold 14px Sans-Serif",
stroke: Black.L500,
textAlign: "center",
stretch: GraphObject.Horizontal,
},
new Binding("text", "name"),
new Binding("stroke", "labelKey", (labelKey) => {
const { color } = labelConfigFromLabelKey(labelKey, labelData);
return color;
})
),
$(
Placeholder, // becomes zero-sized when Group.isSubGraphExpanded is false,
{ row: 1, columnSpan: 2, padding: 10, alignment: Spot.TopLeft, },
new Binding("padding", "isSubGraphExpanded", function (exp) {
return exp ? 10 : 0;
}).ofObject()
)
)
);
And here is your shiftNode function, just changed to be Typescript:
function shiftNodes(group: Group) {
console.log("shifting", group);
group.ensureBounds();
const b = group.actualBounds;
// !!! THESE ARE BOUNDS BEFORE EXPANDED
console.log("b", b.x, b.y, b.width, b.height, b.top, b.bottom, b.left, b.right);
const diagram = group.diagram;
if (diagram === null) return;
const overlaps = diagram.findObjectsIn(b,
function (x) { const p = x.part; return (p?.isTopLevel && p instanceof Node) ? p : null; },
function (node) { return node !== group && !node.isMemberOf(group); },
true);
let dx = 0;
let dy = 0;
const shiftsXY = new Set<Part>();
const shiftsX = new Set<Part>();
const shiftsY = new Set<Part>();
overlaps.each(function (node) {
const r = node.actualBounds;
if (r.contains(b.right, b.bottom)) {
dx = Math.max(dx, b.right - r.left);
dy = Math.max(dy, b.bottom - r.top);
shiftsXY.add(node);
} else if (b.contains(r.left, r.bottom)) {
dx = Math.max(dx, b.right - r.left);
shiftsX.add(node);
} else if (b.contains(r.right, r.top)) {
dy = Math.max(dy, b.bottom - r.top);
shiftsY.add(node);
}
});
if (dx > 0) diagram.moveParts(shiftsX, new Point(dx + 10, 0), false);
if (dy > 0) diagram.moveParts(shiftsY, new Point(0, dy + 10), false);
if (dx > 0 && dy > 0) diagram.moveParts(shiftsXY, new Point(dx + 10, dy + 10), false);
}