Keeping the nodes fixed in a group

I have created a group and in the groups nodes are added dynamically. I have used grouptemplate and node template. I can rotate the group and the nodes are rotating in the group accordingly (using rotateMultipletool). I want to keep the nodes fixed in the group while dragging. How to do that ?

I’m unsure of what you mean. Could you please post several small screenshots showing the current situation both before and after rotating and dragging? And what you want instead?

Please check this is before. Yellow area is the group and blue ones are nodes.

the linking between nodes are working fine but also they are not fixed in the group, i want to keep them fixed.

this figure shows after:

What is your Group.layout? It looks like you should be using a GridLayout with GridLayout.spacing set to new go.Size(0, 0).
And maybe setting GridLayout.wrappingColumn?

Your Group does not have a Placeholder in it, does it?

this is my Group.layout, no i didn’t use placeholder because it was creating problem with rotation…

var horizontalTopFrontGroupTemplate = 
        $(go.Group, "Auto",
        { rotatable: true,
          locationSpot: go.Spot.TopLeft,
          rotateObjectName: "GROUP_RECTANGLE",
          resizable: false,
          layout: $(go.GridLayout, { comparer: go.GridLayout.smartComparer, spacing: go.Size.parse(1)})
        }, new go.Binding("location", "loc").makeTwoWay(),
          $(go.Panel, "Auto", { name: "GROUP_RECTANGLE"},
              $(go.Shape, "Rectangle", { name: "SHAPE", parameter1: 10, width: 770, height: 85, fill: "lightyellow"}),
              $(go.Shape, "TopFrontSide", { name: "FRONTLINE", parameter1: 10, strokeWidth: 2, width: 770, height: 85}, 
                new go.Binding("stroke", "frontcolor")),
              $(go.TextBlock, {alignment: go.Spot.TopLeft, font: "Bold 12pt Sans-Sherif", width: 20}, new go.Binding("text", "key")),
                ) //$(go.Placeholder, { padding: 10})
          );

What did you mean by “I want to keep the nodes fixed in the group while dragging.”?

Did you want to make the member nodes not movable by the user? If so, set Node.movable to false.

that’s it! nodes are not moving at all )

And yes, one cannot sensibly rotate Groups that have Placeholders, because Placeholder areas are always rectangular in document coordinates.

I am missing something. It worked before but I think something is broken again. While rotating group nodes are not rotating anymore. Here’s a screenshot:

this is my node:

myDiagram.nodeTemplate =
  $(go.Node, "Auto", 
    { rotatable: false, 
      background: "#44CCFF", 
      deletable: false, 
      fromSpot: go.Spot.BottomCenter,  // coming out from right side
      toSpot: go.Spot.BottomCenter, 
      locationSpot: go.Spot.TopLeft,
      movable : false,
      canMove: false,
    }, 
   //new go.Binding("location", "loc"),
   new go.Binding("angle").makeTwoWay(), //save the modified Node.angle in the model data
    $(go.Shape, "Rectangle", {
        toMaxLinks: 1,
        fromMaxLinks: 1,
        width: 75,
        height: 75,
        stroke: "black",
        strokeWidth: 1,
        portId: "",
        cursor: "pointer", 
        fromLinkable: true, fromLinkableSelfNode: false, fromLinkableDuplicates: false,
        toLinkable: true, toLinkableSelfNode: false, toLinkableDuplicates: false
    }, new go.Binding("fill", "color")),
    $(go.TextBlock, "Default text", { margin: 6, font: "bold 18px sans-serif"}, 
    new go.Binding("text", "name").makeTwoWay())
    );

Ah, yes, all Layouts also work on Nodes in document coordinates, so they suffer from the same problem that Group Placeholders have. Each layout only operates in document coordinates, and they do not know about laying out nodes assuming some angle determined by the containing group.

I suppose there could be an extra step in a custom layout that accepted the regular results of the layout and then moved the nodes by revolving them around some point that would be appropriate for the group.

Do you expect the group layout to be performed more than once? Will you be adding or removing nodes from the group? Might the nodes change size? Such changes normally invalidate the layout and thus cause it to be performed again. That is why you see the nodes being laid out again – each node changed size because you rotated it.

i don’t understand everything yet but here are the answers:

Do you expect the group layout to be performed more than once?
i guess yes because the groups might be rotated more than once.
Will you be adding or removing nodes from the group?
No once drawn no more nodes will be added or removed from the group but there will be links drawn or relinked.
Might the nodes change size?
No the nodes will not change size.

and yes normally each nodes should move around the each of their centers while the group is also rotating…

Given your answers, I think there’s an easy solution: set Layout.isOngoing to false.

But it leaves open a question about exactly when you would want the layout to be performed at all. In other words, maybe you shouldn’t have a Group.layout at all.

that solves! but nodes not inside i think that could be because of location hard binding, i have to check more

If no Group.layout then the nodes are not placed horizontally they are in a spaced 3 x 3 grid…

That might be OK if the initial angle of the group is zero, but if the group is at some other angle, an initial layout will be wrong.

Furthermore it seems to me that you would only want to perform the layout when the nodes haven’t already been laid out and thus already have saved locations. If the nodes already have locations, then you don’t want to do an initial layout, which means you would also want to set Layout.isInitial to false. But if both isInitial and isOngoing are false, when are you going to perform the layout?

Yes something with location… was using locationSpot: go.Spot.TopLeft, that created the problem. Using : locationSpot: go.Spot.Center, solves the problem! Using Layout.isInitial vanishes all nodes though.

That’s right – if the Group.layout isn’t performed, and there’s no binding on the Node.location or Node.position, and you haven’t executed some code to assign the member nodes’ locations, then those member nodes won’t have a real location. No real location means there’s nowhere for the node to be drawn.

That makes sense. However, initially I need to set group rotation programmatically. Doing so doesn’t set the nodes to the direction of group. Here’s what I mean :

1601369763888

On the other hand, when using the rotate point manually (using RotateMultipleTool extension) nodes are rotated along with the group i.e works fine.

If you want to rotate a Group programmatically, and the RotateMultipleTool extension operates the way that you want interactively, I suggest that you copy and adapt the code in that tool’s rotate method. You can simplify the code by not having to deal with the user holding down the control key.

Ok that is one option. Currently, I have found a solution from your another answer using wrappingColumn: 1. Here’s my code :

var horizontalTopFrontGroupTemplate = 
        $(go.Group, "Horizontal",
        { rotatable: true,
          locationSpot: go.Spot.Center,
          rotateObjectName: "GROUP_RECTANGLE",
          resizable: false,
          layout: $(go.GridLayout, { comparer: go.GridLayout.smartComparer, wrappingColumn: 1, spacing: go.Size.parse(5), isOngoing : false})
        }, new go.Binding("location", "loc").makeTwoWay(),
         new go.Binding("angle", "angle").makeTwoWay(),
          $(go.Panel, "Auto", { name: "GROUP_RECTANGLE"},
              $(go.Shape, "Rectangle", { name: "SHAPE", parameter1: 10, width: 770, height: 85, fill: "lightyellow"}),
              $(go.Shape, "TopFrontSide", { name: "FRONTLINE", parameter1: 10, strokeWidth: 2, width: 770, height: 85}, 
                new go.Binding("stroke", "frontcolor")),
              $(go.TextBlock, {alignment: go.Spot.TopLeft, font: "Bold 12pt Sans-Sherif", width: 20}, new go.Binding("text", "key")),
                ) //$(go.Placeholder, { padding: 10})
          );

but need to bind it with the property later (like angle), how to do that ? I have tried creating a new binding statement under angle binding but it didn’t work.

nodeDataArray.push({key: "A", isGroup : true, group: "MainGroup", frontcolor:"red", category: "horizontaltopfront",    loc: new go.Point(0,0 * y_coeff), angle: 90}); 

Your node template has a Binding on the Node.angle property, so that should work.