Swim lane Implementation

We have not use any layout

myDiagram =
        $(go.Diagram, "myDiagramDiv", {
            initialContentAlignment: go.Spot.Center,
            commandHandler: new DrawCommandHandler(),
            rotatingTool: new GroupRotatingTool(), 
            scrollMode: go.Diagram.InfiniteScroll,
            //"TextEdited": onTextEdited,
            "ClipboardPasted": ClipboardPasted, 
            "rotatingTool.snapAngleMultiple": 90,
            "rotatingTool.snapAngleEpsilon": 90,
            "commandHandler.arrowKeyBehavior": "move",
            "commandHandler.archetypeGroupData": {
                text: "Group",
                category: "UserDefineGroup",
                isGroup: true
            "panningTool.isEnabled": true,
            "grid.visible": false,
            "allowDrop": true,
            "undoManager.isEnabled": true,
            "LinkDrawn": linkdrawn,
            "linkingTool.portGravity": 20,
            "linkingTool.direction": go.LinkingTool.ForwardsOnly,
            hoverDelay: 600,
            dragSelectingTool: $(RealtimeDragSelectingTool, {
                isPartialInclusion: true,
                delay: 50
            }, {
                box: $(go.Part, // replace the magenta box with a red one
                        layerName: "Tool",
                        selectable: false
                    $(go.Shape, {
                        name: "SHAPE",
                        fill: "rgba(255,0,0,0.1)",
                        stroke: "red",
                        strokeWidth: 2

Now we want to implement Swim Line (Swim Lanes).

 myDiagram =
        $(go.Diagram, "myDiagramDiv",
            // use a custom ResizingTool (along with a custom ResizeAdornment on each Group)
            resizingTool: new LaneResizingTool(),
            // use a simple layout that ignores links to stack the top-level Pool Groups next to each other
            layout: $(PoolLayout),
            // don't allow dropping onto the diagram's background unless they are all Groups (lanes or pools)
            mouseDragOver: function(e) {
              if (!e.diagram.selection.all(function(n) { return n instanceof go.Group; })) {
                e.diagram.currentCursor = 'not-allowed';
            mouseDrop: function(e) {
              if (!e.diagram.selection.all(function(n) { return n instanceof go.Group; })) {
            // a clipboard copied node is pasted into the original node's group (i.e. lane).
            "commandHandler.copiesGroupKey": true,
            // automatically re-layout the swim lanes after dragging the selection
            "SelectionMoved": relayoutDiagram,  // this DiagramEvent listener is
            "SelectionCopied": relayoutDiagram, // defined above
            "animationManager.isEnabled": false,
            // enable undo & redo
            "undoManager.isEnabled": true

here PoolLayout is used. We implement this in our project , we saw all nodes are auto layout. How we can implement without using layout.

Please give an example.

Remove the Group.layout settings.

you are talking to remove “layout: $(PoolLayout),”???

No, the LayeredDigraphLayout in the lane group.

we have not use any layout in group

var node =
                $(go.Group, "Auto",
                    new go.Binding("location", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),

                        isSubGraphExpanded: false,
                        ungroupable: true,
                        subGraphExpandedChanged: function(group) {
                    new go.Binding("isSubGraphExpanded", "isSubGraphExpanded"), {
                        toolTip: myToolTips
                    $(go.Shape, "Rectangle", {
                        fill: background,
                        stroke: null,
                        spot1: go.Spot.TopLeft,
                        spot2: go.Spot.BottomRight
                    }, new go.Binding("stroke"), new go.Binding("fill")),
                    $(go.Panel, "Vertical",
                        $(go.TextBlock, "Center", {
                                name: "txt",
                                row: 0,
                                font: "6pt sans-serif",
                                wrap: go.TextBlock.WrapFit,
                                width: 60,
                                editable: true
                            new go.Binding("text")),
                        $(go.Panel, "Table",
                            $(go.Panel, "Table", {
                                    name: "img",
                                $(go.Picture, icon, {
                                        visible: false,
                                        row: 1,
                                        width: 55,
                                        height: 55,
                                    new go.Binding("visible", "isSubGraphExpanded",
                                        function(exp) {
                                            return exp ? false : true;
                                $("SubGraphExpanderButton", {
                                    row: 1
                                $(go.Placeholder, {
                                        row: 2,
                                        padding: 5
                                    new go.Binding("padding", "isSubGraphExpanded",
                                        function(exp) {
                                            return exp ? 10 : 0;

                        contextMenu: $(go.Adornment, "Vertical", {
                                defaultStretch: go.GraphObject.None
                            $(go.TextBlock, "Ungroup", {
                                width: 100,
                                height: 25,
                                background: '#004780',
                                stroke: '#fff',
                                textAlign: 'center',
                                verticalAlignment: go.Spot.Center,
                                margin: 0
                            { mouseOver: function(e, obj) {
                                var toolTipDIV = document.getElementById('groupsubheadermenu');
                                var pt = e.diagram.lastInput.viewPoint;
                                jQuery('#groupsubheadermenu').html('< Ctrl + Shift + G >');
                                toolTipDIV.style.left = (pt.x + 20) + "px";
                                toolTipDIV.style.top = (pt.y) + "px";
                                mouseLeave: function(e, obj) {
                                    var toolTipDIV = document.getElementById('groupsubheadermenu');
                                    toolTipDIV.style.left = -100 + "px";
                                    toolTipDIV.style.top = -100 + "px";
                                click: function(e, obj) {
                        mouseEnter: function(e, obj, prev) {
                        click: function(e, obj) {
                            var node = obj.part;

                        mouseHover: function(e, obj) {
                            var node = obj.part;
                            if (obj.part.data.__gohashid < 6000) {
                                jQuery('#myPaletteDiv' + obj.part.data.key).show();
                        mouseLeave: function(e, obj) {
                            hidemyToolTip('myPaletteDiv' + obj.part.data.key);
                        // mouseDrop: dropOntoNode

If you have not set Group.layout, then the Nodes that are members of that Group will get whatever position or location that you set or bind. But the PoolLayout will move the Groups.

Can we apply layout only for some group for swim lines. Other groups & nodes without any layout.

Is there any example for such?

When we load

{ "class": "GraphLinksModel",
  "nodeDataArray": [ 
{"key":"Pool1", "text":"Pool", "isGroup":true, "category":"Pool", "loc":"26.59666633605957 0.5"},
{"key":"Pool2", "text":"Pool2", "isGroup":true, "category":"Pool", "loc":"26.59666633605957 473.5"},
{"key":"Lane1", "text":"Lane1", "isGroup":true, "group":"Pool1", "color":"lightblue", "loc":"53.11951383436751 0.5", "size":"323 99.30000000000001"},
{"key":"Lane2", "text":"Lane2", "isGroup":true, "group":"Pool1", "color":"lightgreen", "loc":"53.11951383436751 101.5", "size":"323 179.3"},
{"key":"Lane3", "text":"Lane3", "isGroup":true, "group":"Pool1", "color":"lightyellow", "size":"323 85.589513147722", "loc":"53.11951383436751 282.5"},
{"key":"Lane4", "text":"Lane4", "isGroup":true, "group":"Pool1", "color":"orange", "loc":"53.11951383436751 369.5", "size":"323 85.589513147722"},
{"key":"oneA", "group":"Lane1", "loc":"65.11951383436751 32.5"},
{"key":"oneB", "group":"Lane1", "loc":"151.11951383436752 12.5"},
{"key":"oneC", "group":"Lane1", "loc":"151.11951383436752 62.5"},
{"key":"oneD", "group":"Lane1", "loc":"237.11951383436752 32.5"},
{"key":"twoA", "group":"Lane2", "loc":"65.11951383436751 163.5"},
{"key":"twoB", "group":"Lane2", "loc":"150.11951383436752 113.5"},
{"key":"twoC", "group":"Lane2", "loc":"150.11951383436752 163.5"},
{"key":"twoD", "group":"Lane2", "loc":"292.1195138343675 113.5"},
{"key":"twoE", "group":"Lane2", "loc":"65.11951383436751 243.5"},
{"key":"twoF", "group":"Lane2", "loc":"150.61951383436752 213.5"},
{"key":"twoG", "group":"Lane2", "loc":"320.1195138343675 213.5"},
{"key":"fourA", "group":"Lane4", "loc":"65.11951383436751 381.5"},
{"key":"fourB", "group":"Lane4", "loc":"151.11951383436752 381.5"},
{"key":"fourC", "group":"Lane4", "loc":"237.11951383436752 381.5"},
{"key":"fourD", "group":"Lane4", "loc":"323.1195138343675 381.5"},
{"key":"Lane5", "text":"Lane5", "isGroup":true, "group":"Pool2", "color":"lightyellow", "loc":"53.11951383436751 473.5", "size":"200 85.589513147722"},
{"key":"Lane6", "text":"Lane6", "isGroup":true, "group":"Pool2", "color":"lightgreen", "loc":"53.11951383436751 560.5", "size":"200 85.589513147722"},
{"key":"fiveA", "group":"Lane5", "loc":"65.11951383436751 485.5"},
{"key":"sixA", "group":"Lane6", "loc":"65.11951383436751 572.5"},
{"key":"test node"}
  "linkDataArray": [ 
{"from":"oneA", "to":"oneB"},
{"from":"oneA", "to":"oneC"},
{"from":"oneB", "to":"oneD"},
{"from":"oneC", "to":"oneD"},
{"from":"twoA", "to":"twoB"},
{"from":"twoA", "to":"twoC"},
{"from":"twoA", "to":"twoF"},
{"from":"twoB", "to":"twoD"},
{"from":"twoC", "to":"twoD"},
{"from":"twoD", "to":"twoG"},
{"from":"twoE", "to":"twoG"},
{"from":"twoF", "to":"twoG"},
{"from":"fourA", "to":"fourB"},
{"from":"fourB", "to":"fourC"},
{"from":"fourC", "to":"fourD"}

You can find a node name “test node”.

align as swim line.
We want to apply swim lines for few groups. Other groups & nodes without any layout.

Can you give me an example for this?

You have added that node without adding it to any existing group. That means the node will be a top-level node rather than be a member of any pool group or lane group. And that means the Diagram.layout is responsible for arranging that node, which means it is treated as if it were a pool group.

I recommend that you make sure all nodes are in a lane group. Or did you really want nodes to be outside of any pool? In that case I suggest setting or binding the Part | GoJS API property to false.

The following image is a sample diagram. We want to add Swim lane here, without implementation of any layout. We are placing the node by using loc.

How without layout our diagram & with layout swim lane works?
Please give us a directions.
If have any example such , please share with us.

If you have more than one lane, and if you want to implement each lane by using a Group, then something has to arrange the lanes to be next to each other and all have the same length. Some layout must be responsible for that behavior. That is the purpose of having a pool group whose Group.layout is an instance of PoolLayout.

But there is no problem in not setting Diagram.layout and not setting the lane Group.layout.

let we have two group template say Userdefinegroup and Swim lane.
Userdefinegroup is created using Ctrl + G. using

"commandHandler.archetypeGroupData": {
                text: "Group",
                category: "UserDefineGroup",
                isGroup: true

when Initiate Diagram.
Now we want to create Swim line using Alt + G.

When we perform myDiagram.commandHandler.groupSelection(); it set group category ```

How to can create multiple group with different category?

So presumably both the “UserDefineGroup” template and the “Swimlane” template do not have Group.layout set, in order to allow the user to completely control where each node is. That includes where instances of “UserDefineGroup” are. But “Swimlane” groups should be positioned and sized by a PoolLayout.

Are you asking how to control which category of group the user creates by the command CommandHandler.groupSelection?

Certainly if you set the “category” property of the CommandHandler.archetypeGroupData object, then all following groupSelection calls will construct that kind of group. But I suggest that you do not allow the user to create swim lane groups using this command. Instead have different commands for adding and for removing lanes. So set deletable to false on the swim lane group template, to avoid accidental lane deletions.

Also, set Part | GoJS API to false on the swim lane group template and on any pool group template, so that if the user selects them they cannot be included in any new group created by the CommandHandler.groupSelection command.

Are you asking how to control which category of group the user creates by the command CommandHandler.groupSelection ? — Yes.
How can we create two different type group with CommandHandler.groupSelection?

I just answered that question in my reply.

Is there any other way to create a group without using CommandHandler.groupSelection?

Of course you can implement it yourself, but it is probably more complicated than you might think handling all of the possible cases.

Creating a group requires adding appropriate data to the model.

Modifying existing nodes can be done either by setting properties on their data (through the model, of course) or by setting GraphObject/Node properties such as Part.containingGroup.

Perform all of the changes within a single transaction.

Is it possible to draw different width swim lane?
Please check the image below.

If you , how we can achieve this.
Now we are following Swim Lanes example.

It is PoolLayout that is responsible for setting the length of each lane to be the as long as the longest lane.

If you want to allow each lane to have its own length, I think you could try commenting out the PoolLayout.prototype.doLayout override.