groupTemplate position changes after adding nodes

I am new to GoJS and looking for help. This is my default layout view

After adding nodeData the layout changes to something like

Here is my code:

‘’’
myDiagram.groupTemplate =
(go.Group, "Auto", { layout: (go.GridLayout, { spacing: new go.Size(15, 15)}),
movable: false, selectable: false },
new go.Binding(“position”, “pos”, go.Point.parse).makeTwoWay(go.Point.stringify),
(go.Shape, "RoundedRectangle", {strokeDashArray:[8,4] }, new go.Binding("stroke", "strokeColor"), new go.Binding("fill", "fillColor"), new go.Binding("desiredSize", "size", go.Size.parse) ), (go.Placeholder, { padding: 10 })
);

nodeDataArray: [
{“key”:“G1”, “isGroup”:true, “pos”:“0 50”, “size”:“405 100”, “fillColor”: “#ffffff”, “strokeColor”: “#cacecd” },
{“key”:“G2”, “isGroup”:true, “pos”:“0 155”, “size”:“250 200”, “fillColor”: “#f0f3fa”, “strokeColor”: “#57bdeb”},
{“key”:“G3”, “isGroup”:true, “pos”:“255 155”, “size”:“150 200”, “fillColor”: “#f0f3fa”, “strokeColor”: “#57bdeb”},
{“key”:“G4”, “isGroup”:true, “pos”:“0 360”, “size”:“405 100”, “fillColor”: “#ffffff”, “strokeColor”: “#cacecd”},
{ key: 1, group: “G1”},
{ key: 2, group: “G4”},
{ key: 3, group: “G2”},
{ key: 4, group: “G2”},
{ key: 5, group: “G2”},
{ key: 6, group: “G3”},
{ key: 7, group: “G3”},
{ key: 8, group: “G2”},
]
‘’’
How do I control the position change of the template group after adding nodes.

It’s because an “Auto” Panel by default will place its non-main elements (i.e. the Placeholder) in the middle of the main element (i.e. the Shape whose size has been set via the binding).

One solution is to just remove the “Auto” type from the Group template:

  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          "undoManager.isEnabled": true
        });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(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,
        { layout: $(go.GridLayout, { spacing: new go.Size(15, 15) }),
          movable: false, selectable: false },
        new go.Binding("position", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
        $(go.Shape, "RoundedRectangle", {strokeDashArray:[8,4] },
          new go.Binding("stroke", "strokeColor"),
          new go.Binding("fill", "fillColor"),
          new go.Binding("desiredSize", "size", go.Size.parse) ),
        $(go.Placeholder, { padding: 10 })
      );

    myDiagram.model = new go.GraphLinksModel([
      {"key":"G1", "isGroup":true, "pos":"0 50", "size":"405 100", "fillColor": "#ffffff", "strokeColor": "#cacecd" },
      {"key":"G2", "isGroup":true, "pos":"0 155", "size":"250 200", "fillColor": "#f0f3fa", "strokeColor": "#57bdeb"},
      {"key":"G3", "isGroup":true, "pos":"255 155", "size":"150 200", "fillColor": "#f0f3fa", "strokeColor": "#57bdeb"},
      {"key":"G4", "isGroup":true, "pos":"0 360", "size":"405 100", "fillColor": "#ffffff", "strokeColor": "#cacecd"},
      { key: 1, group: "G1"},
      { key: 2, group: "G4"},
      { key: 3, group: "G2"},
      { key: 4, group: "G2"},
      { key: 5, group: "G2"},
      { key: 6, group: "G3"},
      { key: 7, group: "G3"},
      { key: 8, group: "G2"},
      ]);
  }
1 Like

Walter, Thank you so much. That fixed the issue.
I am having another issue with linking the nodes. Ideally I need tp achieve the following with linking the nodes.

  1. Nodes in box A and D, should to placed horizontally.
  2. Nodes in box B, links should not overlap each other. And nodes should be placed in that manner dynamically.
  3. All nodes will have more than one connecting point. It’s decided dynamically.
  1. It sounds like you want groups A and D to have Group.layout set to a GridLayout with GridLayout.wrappingWidth set to a large number (if you really want there to be only one row) or to the width of A or D minus the Placeholder.padding (if you might have multiple rows).

  2. I don’t understand what you mean by “nodes should be placed in that manner dynamically”. If you want users to manually position the nodes, you should not set Group.layout for group B (or C?). Or else the Group.layout should be responsible for positioning the nodes automatically.

It’s easy to get links not to cross over nodes if you set Link.routing to go.Link.AvoidsNodes. However, that routing does not ensure that no segments of different link paths will coincide. There might be some remedies, but we can deal with that later.

Normally the layout will ensure that nodes do not overlap each other. However if you are expecting users to drag nodes around, then you can prevent the nodes being dragged from overlapping other nodes by customizing the dragging operation. https://gojs.net/latest/samples/dragUnoccupied.html

  1. I would guess that you should set fromSpot and toSpot on each node to be go.Spot.AllSides. https://gojs.net/latest/intro/connectionPoints.html

my linktemplate and model is like this
‘’’
myDiagram.linkTemplate =
(go.Link, { routing: go.Link.Orthogonal, corner: 4 , curve: go.Link.JumpOver, }, (go.Shape),
$(go.Shape, { toArrow: “Standard” })
);

myDiagram.model = new go.GraphLinksModel([
{“key”:“G1”, “isGroup”:true, “pos”:“0 50”, “size”:“405 100”, “fillColor”: “#ffffff”, “strokeColor”: “#cacecd” },
{“key”:“G2”, “isGroup”:true, “pos”:“0 155”, “size”:“250 200”, “fillColor”: “#f0f3fa”, “strokeColor”: “#57bdeb”},
{“key”:“G3”, “isGroup”:true, “pos”:“255 155”, “size”:“150 200”, “fillColor”: “#f0f3fa”, “strokeColor”: “#57bdeb”},
{“key”:“G4”, “isGroup”:true, “pos”:“0 360”, “size”:“405 100”, “fillColor”: “#ffffff”, “strokeColor”: “#cacecd”},
{ key: 1, group: “G1”},
{ key: 2, group: “G4”},

        { key: 3, group: "G2"},
        { key: 4, group: "G2"},
        { key: 5, group: "G2"},

        { key: 6, group: "G3"},
        { key: 7, group: "G3"},

         ],
        [
        { from: 6, to: 3 },
        { from: 7, to: 4 },

    ]);

‘’’
I need the links in two different lines than in one single line. Please ref. to my earlier diagram with nodes and links.Also how to connect to a node in different ports each time there is a link. please point out to any code sample. Thanks.

Try what I suggested above: set Link.routing to go.Link.AvoidsNodes .

For the nodes, set fromSpot and toSpot to be go.Spot.AllSides .

Yes. I am doing that. Please check here
https://codepen.io/KrishNine/pen/OJyvqZo

The links are trying to avoid the groups. Set Group.avoidable to false.

Have updated the codepen, https://codepen.io/KrishNine/pen/OJyvqZo.

  1. How do I connect to a new port on a node each time I have a new link. Right now I see a single port of connect on a node? For Ex, links between 6-3 and 6-5 should show two connecting ports on 6.
  2. When I click on a node and drag, the diagram is moving. I tried e.diagram.currentCursor = ‘not-allowed’; but it’s not working. Am I missing something here?
  3. Ideally I need to place
    G1 - Nodes to the center of the group and towards the bottom
    G2 - Nodes positioning the nodes automatically
    G3 - Nodes vertical and towards the left
    G4 - Nodes to the center of the group
    Have tried using groupTemplateMap.add (check https://codepen.io/KrishNine/pen/NWGMWGz) for G1, but its positioning the G1 nodes outside the group. Is my approach to the diagram layout/groupTemplate is correct? Please suggest the best approach for my use case.
<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Sample</title>
<!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
<meta charset="UTF-8">
<script src="go.js"></script>
<script id="code">
  function PositionLayout() {
    go.Layout.call(this);
  }
  go.Diagram.inherit(PositionLayout, go.Layout);

  PositionLayout.prototype.doLayout = function(coll) {
    var parts = this.collectParts(coll);
    this.diagram.commit(function() {
      parts.each(function(p) {
        if (p instanceof go.Node) {
          var x = p.data.x;
          var y = p.data.y;
          if (!isNaN(x) && !isNaN(y)) p.moveTo(x, y);
        }
      });
    });
  }

  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          layout: new PositionLayout(),
          allowZoom: false,
          allowHorizontalScroll: false,
          allowVerticalScroll: false,
          "linkingTool.direction": go.LinkingTool.ForwardsOnly,
          "undoManager.isEnabled": true,
          "ModelChanged": function(e) {
            if (e.isTransactionFinished) {
              document.getElementById("mySavedModel").textContent = myDiagram.model.toJson();
            }
          }
        });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        { selectable: false },
        $(go.Shape,
          {
            fill: "white", portId: "",
            fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides,
            fromLinkable: true, toLinkable: true
          }),
        $(go.TextBlock,
          { margin: 10 },
          new go.Binding("text", "key"))
      );

    myDiagram.groupTemplate =
      $(go.Group, "Auto",
        {
          selectable: false,
          avoidable: false,
          margin: 5,
          desiredSize: new go.Size(200, 200)
        },
        new go.Binding("desiredSize", "size", go.Size.parse),
        new go.Binding("layout", "alignment", function(lay) {
          if (lay.equals(go.Spot.Top) || lay.equals(go.Spot.Bottom)) {
            return $(go.GridLayout,
              { wrappingWidth: 9999, spacing: new go.Size(20, 20) });
          }
          if (lay.equals(go.Spot.Left) || lay.equals(go.Spot.Right)) {
            return $(go.GridLayout,
              { wrappingColumn: 1, spacing: new go.Size(20, 20) });
          }
        }),
        $(go.Shape, "RoundedRectangle",
          { fill: "transparent", strokeDashArray: [8, 4] },
          new go.Binding("stroke", "strokeColor"),
          new go.Binding("fill", "fillColor")),
        $(go.Placeholder,
          { padding: 10 },
          new go.Binding("alignment")),
        $(go.TextBlock,
          { alignment: go.Spot.TopLeft, font: "bold 12pt sans-serif" },
          new go.Binding("text", "key"))
      );

    myDiagram.linkTemplate =
      $(go.Link,
        {
          routing: go.Link.AvoidsNodes,
          corner: 4, curve: go.Link.JumpOver
        },
        $(go.Shape),  // the path
        $(go.Shape, { toArrow: "Standard" }),  // the arrowhead
        $(go.Shape,  // the endpoint
          {
            segmentIndex: -1,
            segmentOffset: new go.Point(4, 0),
            width: 8, height: 8,
            fill: "gray", strokeWidth: 0
          })
      );

    myDiagram.model = new go.GraphLinksModel([
      { key:"G1", isGroup:true,
        x: 0, y: 0, size: "620 200",
        alignment: go.Spot.Bottom,
        fillColor: "#ffffff", strokeColor: "#cacecd" },
      { key:"G2", isGroup:true,
        x: 0, y: 220, size: "400 200",
        fillColor: "#f0f3fa", strokeColor: "#57bdeb" },
      { key:"G3", isGroup:true,
        x: 420, y: 220, size: "200 200",
        alignment: go.Spot.Left,
        fillColor: "#f0f3fa", strokeColor: "#57bdeb" },
      { key:"G4", isGroup:true,
        x: 0, y: 440, size: "620 200",
        fillColor: "#ffffff", strokeColor: "#cacecd" },
      { key: 1, group: "G1"},
      { key: 2, group: "G1"},
      { key: 3, group: "G2"},
      { key: 4, group: "G2"},
      { key: 5, group: "G2"},
      { key: 6, group: "G3"},
      { key: 7, group: "G3"},
      { key: 8, group: "G4"},
      { key: 9, group: "G4"},
    ],
    [
      { from: 3, to: 1 },
      { from: 4, to: 2 },
      { from: 6, to: 3 },
      { from: 6, to: 5 },
      { from: 7, to: 4 },
      { from: 4, to: 8 },
      { from: 5, to: 9 },
    ]);
  }
</script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:800px"></div>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>
</body>
</html>

produces:

1 Like

Walter, thank so much for your help. You are simply amazing :)

You are welcome. That’s why we aren’t open source.

Make sense.

For Nodes 1 and 2. I am trying use a different node template. Though I am using ‘go.Spot.Bottom’ the link is still randomly placed.

‘’’
var simpleTemplate =
(go.Node, "Auto", (go.Shape, “Rectangle”,
{ margin: 1, fill: “#c0c0c0”, fromSpot: go.Spot.Bottom, toSpot: go.Spot.Bottom }),
(go.TextBlock, new go.Binding("text", "title")), { toolTip: (“ToolTip”,
$(go.TextBlock, { margin: 4 },
new go.Binding(“text”, “desc”))
)
},
);
‘’’

All of those from… and to… properties have to go on the GraphObject that is a port. That would be an object with portId set, or else the whole Node if nothing has portId set.

Could you please point me to any example.

https://gojs.net/latest/intro/connectionPoints.html#ToSpotAndFromSpot
https://gojs.net/latest/api/symbols/GraphObject.html#toSpot

You set the fromSpot and toSpot on the Shape. That’s OK if you also set the portId to an empty string. Or you can move those properties to be on the whole Node, which is the default port if you don’t set portId on any object.

How do I increase the spacing between nodes in ‘G2’ or change the layout only for this group?
Screen Shot 2020-05-21 at 12.39.06 PM

What have you set Group.layout to? The type of layout determines if and how you can control its behavior.

Its in Auto, https://codepen.io/KrishNine/pen/OJyvqZo