Location of nodes relative to their containers

Hi,
So for my use case, I have to render very large layouts. The nodeDataArray is generated by parsing code into tokens. What I want is to lay out the generated nodes in a nice, grid format inside a parent container (a group). There are two things that I wish to ask here:

  1. I would be setting a fixed width for my parent container, laying it out as a grid structure based on positions, with maximum 4 nodes per row. I want to be able to control where these nodes are placed by setting a property for each node object in the nodeDataArray. So for example, the node with position 1 would occupy the very first position in the first row, and the node with position 6 would occupy the second position in the second row. In short, I want gojs to read these position properties set by me in each node object and position these nodes accordingly when I generate a graphLinksModel from my nodeDataArray. How can I achieve such a thing?

  2. Secondly, since I am creating these layouts on the backend and then sending them to the front-end to be rendered (I bind location property property for each node with the location in the templates that I define on front-end), I want my nodes to have their location properties set relative to their parent containers. So imagine a container placed at (100,100). The first child inside that container should have the location (0,0), which means that it is placed at the top-left corner of its parent container. How can I achieve this?

  1. Use something like this in your Group template:
layout: $(go.GridLayout,
  {
    wrappigColumn: 4,
    sorting: go.GridLayout.SortingAscending,
    comparer: (a, b) => a.data.position - b.data.position,
    . . .
  })

where data.position always has a number indicating the order position for that node.

  1. Why do you need that behavior? What is the Diagram.layout? Any such layout will move each Group as if it were an atomic node, preserving the relative positionings of the group’s member nodes.

Thanks for your response. The response for my first query is exactly something that I was looking for.

  1. In my case, I can have one, or more than one level 1 groups. Each of these groups can have other groups and nodes inside them (which we only display upon clicking the expand button). Our diagrams are very large and we just want to perform the layouts in the backend, store them in a database and serve them to the front-end for rendering. The problem is that we can have one or more of these level1 groups which we wish to display together on our front-end, but because of computational and storage complexities, we can not lay them out on our backend at once. So to summarise, we lay out each level1 group on our backend alone, saving it in some place, and then we combine all of these level1 groups and send them to the front-end via an api call. Since each of these groups was laid out separately on the backend, combining them from different sources to display them together on front-end would create an overlap.
    This is why I was thinking that if each child of these level1 groups had its location relative to its parent group, then when combining these different level1 groups, we would only have to arrange them in a circular layout, without having to calculate the locations for each of their child nodes, saving us time and computation.

But what layouts are you using? The Group.layout above is a GridLayout, which is very fast. There’s no reason to precompute those layouts. Do you have different Group.layouts or Diagram.layout?

Could you please quantify how many nodes and groups you might possibly have? Are you going to load a group’s member nodes the first time that it is expanded? This is just like what the Incremental Tree sample does, except it does it for expanding trees the first time, not for expanding groups. But the same ideas apply.

Hi Walter,
Thank you for your response. I am using LayeredDigraphLayout which is slower, considering especially that I can have nodes well in the range 5000-10,000, of these, I can have around 2000 groups, or more. Please feel free to have a look here CodeMaps. If you open the console, you can see the data being console logged as well.

Are you going to load a group’s member nodes the first time that it is expanded?

All of the data is loaded in a single api call, and I use isSubGraphExpanded property to hide or show the children nodes/groups.

If you upgrade to GoJS v2.3, you can set LayeredDigraphLayout.alignOption to some value such as go.LayeredDigraphLayout.AlignAll, and that should make those layouts faster.

Here’s a sample that supports relative locations for group member nodes:

As usual, the complete implementation is in the page itself.

That seems to be it, thank you for sharing. I can not, however, see the full implementation in the link that you shared, I can only see this:

Reminder about what I wrote above:

I see that, and what it implies is that by default, the children nodes inside a group assume positions relative to their containing group. However, I was experimenting with the following code in code-pen, but the children nodes here, Beta and Gamma, would not align themselves in reference to their containing group. Can you please tell me what the issue is with this, as I can’t figure it out?

var $ = go.GraphObject.make;

// Diagram declaration
var diagram = $(go.Diagram, "myDiagramDiv");

diagram.nodeTemplate =
  $(go.Node,
    new go.Binding("location", "loc", go.Point.parse),
    $(go.TextBlock,
      new go.Binding("text", "key"))
  );

diagram.groupTemplate =
  $(go.Group, "Vertical",
    { selectionObjectName: "PH",
      locationObjectName: "PH" },
    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(),
    $(go.TextBlock,  // group title
      { font: "Bold 12pt Sans-Serif" },
      new go.Binding("text", "key")),
    $(go.Shape,  // using a Shape instead of a Placeholder
      { name: "PH",
        fill: "lightyellow" },
      new go.Binding("desiredSize", "size", go.Size.parse))
  );

var nodeDataArray = [
  { key: "Beta", group: "Omega", loc: "0 0" },
  { key: "Gamma", group: "Omega", loc: "125 75" },
  { key: "Omega", isGroup: true, loc: "50 50", size: "150 50" },
];
diagram.model = new go.GraphLinksModel(nodeDataArray);

That’s right – if the group isn’t using a Placeholder, then the group’s location is independent of the locations/areas of its member parts. Or the member nodes have locations that are independent of their containing group. You can look at it either way.