Layout nodes group only once, when the group is created

When i create a group, i would like the nodes to be layout, for example CircularLayout.
After, the group is created, i would like to avoid auto layout and let the user arrange the nodes within the group.
The default way that i know is to set the { layout: $(go.CircularLayout) } in the group template and after the group is create set the :
group.layout.isInitial =false;
group.layout.isOngoing= false;

I am reluctant to put the layout: $(go.CircularLayout) in the group template because every time a group is created i will have to remember to unset the isInitial and isOngoing values.
Is there any other way to layout group nodes without setting the layout in the template ?

Seems to me that you want the value of Group.layout’s Layout.isInitial to be the default value of true. You only need to set Layout.isOngoing to false.

I suppose if you really want to control such layouts entirely programmatically, you could leave the Group.layout to always have both isInitial and isOngoing false. Then you can choose to set Layout.isValidLayout to false only on those group layouts that you want to re-lay-out. To actually perform the invalid layouts, call Diagram.layoutDiagram with no argument (or argument false).

I see, going the opposite way.
i set the isInitial and the isOngoing to false in the group template and right after the group is created (setTimeout…200), i set the group.layout.isValidLayout to false and called layoutDiagram,
But the nodes are not layed out…

I just tried it in a simple app, setting Layout.isInitial and Layout.isOngoing to false on all Layouts. At first upon load nothing would show, because no nodes had real locations. So I called myDiagram.layoutDiagram(true), and everything was laid out normally.

I then selected some nodes and created a new Group. The group was created with its member nodes not moving at all. Those member nodes weren’t arranged nicely, and the Group was already selected, so I did:

myDiagram.selection.first().layout.isValidLayout = false;
myDiagram.layoutDiagram();

That new group, and only that new group, got its members laid out properly.

But that left the new group in the wrong location, overlapping other groups. So I did:

myDiagram.layout.isValidLayout = false;
myDiagram.layoutDiagram();

And the top-level nodes (I think all Groups in my case) all got laid out well.

So, everything worked as I expected.

Walter,
To be honest, i’m frustrated.
I’m the only one in my group that is defending GOJS.
Everyone in my department wants to replace GOJS with another application.
I fight them on a daily basis.
There are some subjects in GOJS platform which are not intuitive and are not clear to me : the Part position/location (i cannot understand why x or y can have negative values) and group layouts.
Every time i’m trying to locate a part or open a group it behaves abnormal. Unfortunately, my application is dealing with moving parts and opening groups, 80% of its use case, making my end users very frustrated
In your last response you didn’t mention anything about templates, so i don’t know how to fix my code.
Should i create template with both isInitial and isOngoing set to false ?
Should i set group.layout.isValidLayout to false, after creating the group ?
Should i call diagram.layoutDiagram() ?
I’m lost…
The use case is like that :
For simplicity, let’s say that i have 10 nodes which have predefined location (binded with “loc”)
I press a button that creates a group holding those nodes. The nodes in the group should be circle layout and the group is created collapsed.
Then, the user can expand the group and “move” the nodes within the group.
After that, the user saves the diagram to JSON (saving the nodes “loc”) and can load the diagram from JSON. As soon as the diagram is loaded from JSON, the nodes and the group should have the same location when they were saved.
Forget the JSON thing, let’s focus on group creation.
Please let me know what code to write in order to create a group with particular layout, but the layout should be executed only once, when the group is created.
Currently, your suggestions are not working, don’t know why…
I can send you the code…

OK, I just created a sample app that I believe does everything that you just asked for:

<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Sample</title>
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
<meta charset="UTF-8">
<script src="go.js"></script>
<script id="code">
  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
          {
            "undoManager.isEnabled": true,
            "animationManager.isEnabled": false,
            "clickCreatingTool.archetypeNodeData": { text: "Node", color: "white" },
            "commandHandler.archetypeGroupData": { isGroup: true, text: "Group" },
            "SelectionGrouped": function(e) {
              e.subject.layout.isValidLayout = false;
              e.diagram.layoutDiagram();
              e.subject.isSubGraphExpanded = false;
            }
          });

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

    myDiagram.groupTemplate =
      $(go.Group, "Vertical",
        {
          locationSpot: go.Spot.Center,
          layout: $(go.CircularLayout, { isInitial: false, isOngoing: false }),
          ungroupable: true,
          subGraphExpandedChanged: function(group) {
            group.type = group.isSubGraphExpanded ? go.Panel.Vertical : go.Panel.Auto;
          }
        },
        new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding("isSubGraphExpanded").makeTwoWay(),
        $(go.Panel, "Auto",
          $(go.Shape, { fill: "lightgray", strokeWidth: 2 },
            new go.Binding("stroke", "color")),
          $(go.Placeholder, { padding: 5 })
        ),
        $(go.Panel, "Horizontal",
          { margin: 4 },
          $(go.TextBlock, { font: "bold 12pt sans-serif" },
            new go.Binding("text").makeTwoWay()),
          $("SubGraphExpanderButton")
        )
      );

    myDiagram.linkTemplate =
      $(go.Link,
        {
          relinkableFrom: true, relinkableTo: true,
          reshapable: true, resegmentable: true
        },
        $(go.Shape),
        $(go.Shape, { toArrow: "OpenTriangle" })
      );

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
      { key: 4, text: "Delta", color: "pink" }
    ]);
  }

  function save() {
    myDiagram.model.modelData.position = go.Point.stringify(myDiagram.position);
    var str = myDiagram.model.toJson();
    document.getElementById("mySavedModel").value = str;
  }
  function load() {
    var str = document.getElementById("mySavedModel").value;
    myDiagram.model = go.Model.fromJson(str);
    var pos = myDiagram.model.modelData.position;
    if (pos) myDiagram.initialPosition = go.Point.parse(pos);
  }
</script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <button id="loadModel" onclick="load()">Load</button>
  <button id="saveModel" onclick="save()">Save</button>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>
</body>
</html>

I guess you’ll have to control-drag-copy (or copy-paste) the existing nodes so that you have more of them that you can group using control-G and ungroup using shift-control-G.

How does a group is created in your code ?
What is “SelectionGrouped” ?
How do i copy/paste my code like you did. I want to send you mine, since it is very similar to your code…yet not working…

CommandHandler.groupSelection is what makes a Group out of some selected Nodes (which might include some existing Groups). CommandHandler.ungroupSelection removes a selected Group and promotes its members to be members of whatever the Group had been a member of.

Those commands are bound to Control-G and Control-Shift-G, by default. There is documentation for those commands and examples in various places, such as the Basic sample. CommandHandler | GoJS API and Basic GoJS Sample

“SelectionGrouped” is a DiagramEvent. GoJS Events -- Northwoods Software

The code it wrote is similar to your code, the only difference is that the user does not select nodes but press a button.
I sent u my code. Please take a look at it. Where have i go wrong ?
Regards,
Tany

Your groupNodes function make a bunch of model data changes, but does not do so within a transaction. But I don’t know if that would explain whatever problem you have.

I have compared my code to yours.
The only difference between the codes is that you call layoutDiagram() while the group is expanded and right after that you callpase the group by setting isSubGraphExpanded to false.
I changed the code accoridanly and it worked perfect.
By the way i use the same method in layouting the diagram. Works fine !!!
So this method of layouting the group before collapsing it , saving and restoring Diagram position (other thread), saving and restoring Group position (other thread) makes my application usable.
This week, my customers were happy to see the change. Back in Business.
Thanks
Tany

Yes, it does not make sense to do a layout of a bunch of nodes and links when they are not visible because the group that they are in is collapsed. Generally, layouts ignore Parts that are not Part.isVisible().

The other way to look at it is that you wouldn’t want layouts to waste time arranging not-visible nodes. Say you had a hundred groups each with a hundred member nodes and links, but all of the groups were collapsed.

Yep,
it does not make sense to put “bandwidth” on non Visible parts.
Thanks