How to make the nodes added to the group horizontally centered when the group uses the go.GridLayout layout

Here’s some code that I think implements what was originally asked for. It does not use any new functionality in GoJS. Well, at least none that is relevant to the problem.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.Shape, { fill: "white" }),
    $(go.TextBlock,
      { margin: 8, editable: true },
      new go.Binding("text").makeTwoWay())
  );

// Assume this is used as a Group.layout
class CenteringGridLayout extends go.GridLayout {
  // As an extra step in doLayout, shift all of the Group.memberParts so that the
  // whole group remains horizontally centered at the same point in document coordinates
  commitLayers(layerRects, offset) {
    if (this.group === null) return;
    // BUG!? when the first member node is added, the group's actualBounds have been updated already,
    // even before doLayout is called.  That causes the group's location to shifted before
    // this layout can try to maintain the location.x value of the group
    const x = this.group.actualBounds.centerX;
    const mbnds = this.diagram.computePartsBounds(this.group.memberParts);
    if (!isNaN(x) && mbnds.isReal()) {
      const dx = x - mbnds.centerX;
      this.diagram.moveParts(this.group.memberParts, new go.Point(dx, 0));
    }
  }
}  // end CenteringGridLayout

myDiagram.groupTemplate =
  $(go.Group, "Vertical",
    {
      locationSpot: go.Spot.Top,  // must have Spot.x === 0.5
      layout: $(CenteringGridLayout, { wrappingColumn: 6 }),
      doubleClick: (e, grp) => {  // add a node to the group
        const ctr = grp.getDocumentPoint(go.Spot.Center);  // start new node at center of group
        e.diagram.model.commit(m => {
          const loc = grp.location.copy();
          m.addNodeData({ text: "new node", group: grp.key, loc: go.Point.stringify(ctr) });
          // BUG: the next two lines (and remembering the original location, above)
          // are necessary to keep the group at the original location,
          // for the first 2 additions to the group
          grp.ensureBounds();
          grp.move(loc, true);
        });
      }
    },
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
    $(go.TextBlock, new go.Binding("text")),
    $(go.Panel, "Auto",
      $(go.Shape, { fill: "#00000008", minSize: new go.Size(400, NaN) }),
      $(go.Placeholder, { padding: 10, alignment: go.Spot.Top })
    )
  );

myDiagram.model = new go.GraphLinksModel(
[
  { key: 0, text: "Double click to add a member node", isGroup: true, loc: "0 0" },
]);
  </script>
</body>
</html>
1 Like