How do I group node across the lane

I use PoolLayout. ( Swim Lanes (vertical) )

I want group nodes like this.

I think this layout needs to “group layout”.

The PoolLayout is reponsible for arranging the “lanes” next to each other, with the same lengths. Each “lane” is implemented by a Group.

The PoolLayout is not responsible for positioning the nodes within the lanes/groups.

In the Swim Lanes samples, each lane/group has its own Group.layout that is responsible for positioning the nodes within the lane. Those samples use LayeredDigraphLayout, but the Kanban sample uses GridLayout. Kanban Board

I am guessing that you want to use a special layout that keeps nodes in their assigned lanes, but still positions the nodes vertically relative to each other when there is any relationship (perhaps indirect) defined by links.

I think I have an example of that. Let me look for it or develop it anew for you, please.

Ah, I found it: Alignment of nodes in Swimlane - #5 by walter

Basically, if you have seen the Beat Paths sample, Beat Paths, the same model has been augmented by having each node know which lane it belongs in by assigning each node to a group.

Take a look at SwimLaneLayout extension: Beat Paths with Lanes for Divisions Using SwimLaneLayout
It is implemented at:
It is documented at: SwimLaneLayout | GoJS API

That sample actually organizes the data into two different ways – either into 8 groups/lanes, or into 2 groups/lanes.

You just need to add the groups (lanes) to your model data, and assign each node to a group (lane). Then use the SwimLaneLayout instead of a regular LayeredDigraphLayout. The complete implementation is on that sample page.

'SwimLaneLayout.html ’ nodes have single group.
And this graph toggle layout by radio button.

var model = new go.GraphLinksModel();
      model.nodeDataArray = (a === 'c' ? nodeDataArrayByConf : nodeDataArrayByDiv);
      model.linkDataArray = linkDataArray;
      myDiagram.model = model;
var nodeDataArrayByDiv = [
        { key: "AFCE", isGroup: true },
        { key: "AFCN", isGroup: true },
        { key: "AFCS", isGroup: true },
        { key: "AFCW", isGroup: true },
        { key: "NFCE", isGroup: true },
        { key: "NFCN", isGroup: true },
        { key: "NFCS", isGroup: true },
        { key: "NFCW", isGroup: true },
        { key: "NE", group: "AFCE" },
        { key: "PIT", group: "AFCN" },
        { key: "DAL", group: "NFCE" },

But, I want multiple grouping.
Now, My diagram like this

"nodeDataArray": [
  {"key":"Pool1", "text":"fads", "isGroup":true, "category":"Pool", "description":"fsda", "loc":"0.5 73.52450866699219"},
  {"key":"1", "text":"ユーザー", "isGroup":true, "group":"Pool1", "color":"#99cfe5", "size":"200 400", "source":"", "loc":"0.5 143.52450866699218"},
  {"key":"2", "text":"サポートデスク", "isGroup":true, "group":"Pool1", "color":"#ecacb5", "size":"200 400", "source":"", "loc":"205.5 143.52450866699218"},
  {"key":"3", "text":"システム管理者", "isGroup":true, "group":"Pool1", "color":"#95dfd6", "size":"200 400", "source":"", "loc":"410.5 143.52450866699218"}
  {"group":"1", "text":"新しい作業", "manual_url":"", "loc":"12.5 271", "key":-6},
  {"group":"2", "text":"新しい作業", "manual_url":"", "loc":"222.5 283", "key":-5},
  {"group":"3", "text":"新しい作業", "manual_url":"", "loc":"432.5 374", "key":-7}

I want this.

What behaviors do you expect such objects to have? Can they be selected, moved, copied, deleted? If so, what effects do those actions have? What happens when one moves or resizes nodes that are inside those objects? There may be nodes within the area of such an object that do not “belong” to that object?

this object can be movable, selectable and deletable. But, this is not group object.
If I move this object, inside nodes position do not change.


            $(go.Part, "Auto",
                zOrder: 0,
                cursor: data.editable ? "move" : "default",
                movable: data.editable,
                deletable: data.editable,
                selectable: data.editable,
                resizable: true,
                resizeObjectName: "SURROUNDBLOCK",
              new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
              $(go.Shape, "Rectangle",
                  fill: "#FFFFEF",
                  portId: ""

node template

$(go.Shape, "Rectangle",  // this is the resized object
                  name: "SHAPE", fill: "#ebebeb", stroke: "#ffffff", strokeWidth: 5,
                  doubleClick: function (e, node) {
                    if (!data.editable) {
                    myDiagram.startTransaction('add node');
                    const groupData =;
                    const x = parseFloat(groupData.loc.split(' ')[0], 10) + parseFloat(groupData.size.split(' ')[0] / 2, 10) - 90;
                    const newData = {
                      group: groupData.key,
                      text: "新しい作業",
                      manual_url: "",
                      loc: x + " " + (e.documentPoint.y - 20)
                    myDiagram.commitTransaction('add node');
                    const groupHeight = parseFloat(groupData.size.split(' ')[1], 10)
                    if (e.documentPoint.y + 100 > (groupHeight + parseFloat(groupData.loc.split(' ')[1], 10))) {
                      myDiagram.model.nodeDataArray.filter(function (node) {
                        return node.isGroup && === "Pool1"
                      }).forEach(function (node) {
                        node.size = `${parseFloat(node.size.split(' ')[0], 10)} ${groupHeight + 100}`
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)),
                {padding: 12, alignment: go.Spot.TopLeft}),
              $(go.TextBlock,  // this TextBlock is only seen when the swimlane is collapsed
                  name: "LABEL",
                  font: "bold 13pt sans-serif",
                  editable: data.editable,
                  angle: 90, alignment: go.Spot.TopLeft, margin: new go.Margin(4, 0, 0, 2)
                new go.Binding("visible", "isSubGraphExpanded", function (e) {
                  return !e;
                new go.Binding("text", "text").makeTwoWay())
            )  // end Auto Panel
          );  // end Group

But, when I resize this object, It becomes this.

I want this object accross the group lane.

My Hope is this yellow ‘part object’ can move freely over the swimlane layout.
(I think I should add ‘Foreground layer’ above swimlane layout.)

OK, so it sounds to me as if you want those yellow “SurroundBlock” Parts not to belong to any Group. That would give them the freedom to be anywhere without affecting any Group and without being affected by any Group.

So your “SurroundBlock” node template looks like a good start. But I have some suggestions.

You might want to place all of those "SurroundBlock"s in a new Layer that is between the layer of the lane Groups and the layer of the regular Nodes. If you have copied the code from the SwimLanes or Kanban samples, those lane Groups are in the “Background” layer, so you will need to create a new Layer and insert it before the default Layer:

myDiagram.addLayerBefore($(go.Layer, { name: "SB" }),

And then set { layerName: "SB" } in your “SurroundBlock” Part template. GoJS Layers -- Northwoods Software

Also I notice that your “SurroundBlock” Part is resizable, but there is no TwoWay Binding on the desiredSize property in order to remember it in the model. GoJS Data Binding -- Northwoods Software