Hey, I’m not sure if it’s useful to post here too, sorry if this is a bit spammy.
Here’s a demo of the node moving problem.
If you select some of the bottom four nodes, group them, and double click the group to expand it you’ll see the group move downwards. This doesn’t happen for the top four as much.
If you change the SelectionGrouped event handler so that it sets the group location instead of calling the move function then expanding the group doesn’t move the nodes.
<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Sample</title>
<!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
<div id="diagram" style="border: solid 1px black; width:100%; height:600px"></div>
<script src="https://unpkg.com/[email protected]"></script>
<script id="code">
const $ = go.GraphObject.make;
const KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
go.Shape.defineFigureGenerator("HalfEllipse", function (shape, w, h) {
return new go.Geometry()
.add(new go.PathFigure(0, 0, true)
.add(new go.PathSegment(go.PathSegment.Bezier, w, .5 * h, KAPPA * w, 0, w, (.5 - KAPPA / 2) * h))
.add(new go.PathSegment(go.PathSegment.Bezier, 0, h, w, (.5 + KAPPA / 2) * h, KAPPA * w, h).close()))
.setSpots(0, 0.156, 0.844, 0.844);
});
go.Shape.defineFigureGenerator("RoundedTopRectangle", function (shape, w, h) {
// this figure takes one parameter, the size of the corner
let p1 = 5; // default corner size
if (shape !== null) {
let param1 = shape.parameter1;
if (!isNaN(param1) && param1 >= 0) p1 = param1; // can't be negative or NaN
}
p1 = Math.min(p1, w / 2);
p1 = Math.min(p1, h / 2); // limit by whole height or by half height?
let geo = new go.Geometry();
// a single figure consisting of straight lines and quarter-circle arcs
geo.add(new go.PathFigure(0, p1)
.add(new go.PathSegment(go.PathSegment.Arc, 180, 90, p1, p1, p1, p1))
.add(new go.PathSegment(go.PathSegment.Line, w - p1, 0))
.add(new go.PathSegment(go.PathSegment.Arc, 270, 90, w - p1, p1, p1, p1))
.add(new go.PathSegment(go.PathSegment.Line, w, h))
.add(new go.PathSegment(go.PathSegment.Line, 0, h).close()));
// don't intersect with two top corners when used in an "Auto" Panel
geo.spot1 = new go.Spot(0, 0, 0.3 * p1, 0.3 * p1);
geo.spot2 = new go.Spot(1, 1, -0.3 * p1, 0);
return geo;
});
const diagram = $(
go.Diagram,
"diagram",
{
layout: $(go.LayeredDigraphLayout, { isInitial: false, isOngoing: false }),
"commandHandler.archetypeGroupData": { isGroup: true },
"SelectionGrouped": e => {
// e.subject.location = e.subject.memberParts.first().location;
e.subject.move(e.subject.memberParts.first().location, true);
},
"undoManager.isEnabled": true,
"draggingTool.isGridSnapEnabled": true,
}
);
diagram.grid =
$(go.Panel, "Grid",
{ visible: true, gridCellSize: new go.Size(30, 30) },
$(go.Shape, "LineH", { stroke: "#E8E8E8" }),
$(go.Shape, "LineV", { stroke: "#E8E8E8" }),
);
const inPortTemplate = $(
go.Panel,
"TableRow",
{},
$(
go.Shape,
"HalfEllipse",
{
angle: 180,
cursor: "pointer",
fromLinkable: false,
fromMaxLinks: 1,
toSpot: go.Spot.Right,
margin: new go.Margin(5, -1, 5, 0),
toLinkable: true,
toMaxLinks: 1,
fill: "black",
desiredSize: new go.Size(9, 18),
},
new go.Binding("portId", ""),
)
);
const outPortTemplate = $(
go.Panel,
"TableRow",
{},
$(
go.Shape,
"HalfEllipse",
{
cursor: "pointer",
fromLinkable: true,
fromMaxLinks: 1,
fromSpot: go.Spot.Right,
margin: new go.Margin(5, 0, 5, -1),
toLinkable: false,
toMaxLinks: 1,
fill: "black",
desiredSize: new go.Size(9, 18),
},
new go.Binding("portId", ""),
)
);
diagram.nodeTemplate = $(
go.Node,
"Horizontal",
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
{ locationSpot: go.Spot.Center },
$(
go.Panel,
"Table",
{
itemTemplate: inPortTemplate,
},
new go.Binding("itemArray", "inPortIds")
),
$(
go.Panel,
"Auto",
{
desiredSize: new go.Size(80, 80),
},
$(
go.Shape,
{ fill: "white" },
new go.Binding("fill", "color")
),
$(go.TextBlock, new go.Binding("text")),
),
$(
go.Panel,
"Table",
{
itemTemplate: outPortTemplate,
},
new go.Binding("itemArray", "outPortIds")
),
);
diagram.groupTemplate = $(
go.Group,
"Table",
{
locationSpot: go.Spot.Center,
ungroupable: true,
isSubGraphExpanded: false,
toSpot: go.Spot.Left,
fromSpot: go.Spot.Right,
},
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
{ doubleClick: (e, grp) => {
if (grp.isSubGraphExpanded) {
e.diagram.commandHandler.collapseSubGraph();
} else {
e.diagram.commandHandler.expandSubGraph();
}
}
},
// If you remove this heading row then you can get the group to align
$(
go.Panel,
"Auto",
{
stretch: go.GraphObject.Horizontal,
row: 0,
column: 0,
},
$(
go.Shape,
"RoundedTopRectangle",
{
strokeWidth: 2,
stroke: "black",
margin: new go.Margin(0, 0, -1.5, 0),
fill: "white",
},
),
$(
go.Panel,
"Vertical",
{
padding: 12,
stretch: go.GraphObject.Fill
},
$(
go.TextBlock,
"Default Text",
{
isMultiline: false,
alignment: go.Spot.Center,
wrap: go.TextBlock.None,
overflow: go.TextBlock.OverflowEllipsis,
maxSize: new go.Size(175, Infinity),
text: "Group Title"
},
),
),
),
$(
go.Panel,
"Auto",
{
stretch: go.GraphObject.Horizontal,
row: 1,
column: 0,
},
$(
go.Shape,
"Square",
{
strokeWidth: 2,
stroke: "black",
fill: "white"
},
),
$(
go.Panel,
"Vertical",
{
stretch: go.GraphObject.Horizontal,
padding: new go.Margin(8, 0, 5, 0),
},
new go.Binding("visible", "isSubGraphExpanded", (isExpanded) => !isExpanded).ofObject(),
$(
go.Panel,
"Vertical",
{
name: "icon",
margin: new go.Margin(0, 10, 0, 10),
},
$(go.TextBlock, {text: "This is a group"}),
$(go.TextBlock, {text: "On two lines"}),
),
),
$(go.Placeholder, { padding: 20 })
)
);
diagram.linkTemplate = $(
go.Link,
{
selectionAdorned: false,
routing: go.Link.Normal,
relinkableTo: true,
fromEndSegmentLength: 10,
toEndSegmentLength: 10,
},
$(
go.Shape,
{
strokeWidth: 3,
},
)
);
diagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue", location: "-300 0", inPortIds: [], outPortIds: ["out"]},
{ key: 2, text: "Beta", color: "orange", location: "-150 0", inPortIds: ["in"], outPortIds: ["out"]},
{ key: 3, text: "Gamma", color: "lightgreen", location: "0 0", inPortIds: ["in"], outPortIds: ["out"]},
{ key: 4, text: "Delta", color: "pink", location: "150 0", inPortIds: ["in"], outPortIds: [] },
// If you remove these nodes then expanding a group doesn't cause such a large movement
{ key: 5, text: "Alpha", color: "lightblue", location: "-300 500", inPortIds: [], outPortIds: ["out"]},
{ key: 6, text: "Beta", color: "orange", location: "-150 500", inPortIds: ["in"], outPortIds: ["out"]},
{ key: 7, text: "Gamma", color: "lightgreen", location: "0 500", inPortIds: ["in"], outPortIds: ["out"]},
{ key: 8, text: "Delta", color: "pink", location: "150 500", inPortIds: ["in"], outPortIds: [] }
],
[
{ from: 1, to: 2, fromPort: "out", toPort: "in" },
{ from: 2, to: 3, fromPort: "out", toPort: "in" },
{ from: 3, to: 4, fromPort: "out", toPort: "in" },
{ from: 5, to: 6, fromPort: "out", toPort: "in" },
{ from: 6, to: 7, fromPort: "out", toPort: "in" },
{ from: 7, to: 8, fromPort: "out", toPort: "in" },
]
);
diagram.model.linkFromPortIdProperty = "fromPort";
diagram.model.linkToPortIdProperty = "toPort";
</script>
</body>
</html>