SwimLaneLayout modification

Hi,

I am using the SwimLaneLayout in GoJS Extension but want to modify its behavior.

By using the given code, if a lane is empty without nodes in it, it does not take any space, as shown below

Screen Shot 2021-12-17 at 11.36.01 PM

However, what I want is to keep the empty lanes a minimum height (as shown below) so that users can drag nodes to it.

Screen Shot 2021-12-17 at 11.36.06 PM

After studying the given SwimLaneLayout example, I modified the commitLayers function by using the top variable to remember the y value of each lane and using the extraSpaces map to adjust the node positions.

commitLayers: function (layerRects, offset) {
              if (layerRects.length === 0) return;

              var rect = layerRects[layerRects.length - 1];
              var totallength = rect.right;

              let extraSpace = 0;
              const extraSpaces = new go.Map();
              let top = 0;

              for (var i = 0; i < laneNames.length; i++) {
                var lane = laneNames[i];
                extraSpaces.set(lane, extraSpace);
                var group = this.diagram.findNodeForKey(lane);
                if (group === null) {
                  this.diagram.model.addNodeData({
                    key: lane,
                    isGroup: true,
                  });
                  group = this.diagram.findNodeForKey(lane);
                }
                group.location = new go.Point(
                  -this.layerSpacing / 2,
                  top + offset.y,
                );
                var ph = group.findObject("PLACEHOLDER");
                if (ph === null) ph = group;

                let laneHeight =
                  this.laneBreadths.get(lane) * this.columnSpacing;
                if (laneHeight === 0) {
                  extraSpace += MIN_LANE_HEIGHT;
                  laneHeight = MIN_LANE_HEIGHT;
                }
                ph.desiredSize = new go.Size(totallength, laneHeight);

                top += laneHeight;
              }

              const nodes = this.diagram.nodes;
              while (nodes.next()) {
                const node = nodes.value;
                const position = nodes.value.position;
                const extraY = extraSpaces.get(node.data.group);
                nodes.value.position = new go.Point(
                  position.x,
                  position.y + extraY,
                );
              }
            },

The code works so far. But I am wondering if it is the recommended approach.

My next question is more generic:

After I studied some extended layout code, I realized that many layout extensions override non-public methods like nodeMinLayerSpace, nodeMinColumnSpace, reduceCrossings, etc. Those methods are not listed in GoJS API.

Where could we find the explanation of those non-public but override-able methods? Is there any comprehensive list? Such list will dramatically ease our job of extending the given layout for our unique use cases.

Looking forward to hearing from you! And happy holidays!

Min

I haven’t tried this to make sure, but instead of what you tried I would modify what computeMinLaneWidth returns. Note the units is columns, not document units.

To partly answer your other question, see the go.d.ts definitions file in the release subdirectory.

Hi Walter,

Thank you so much for your response! what are listed in go.d.ts are exactly what I need!

I will try computeMinLaneWidth. It seems like a much easier approach :)

Min

Hi Walter,

I tried your suggested computeMinLaneWidth approach. It works well with the initial rendering. However, if I interact with the diagram and update its model, which causes the layout re-rendering, each empty lane shrank to a single line again.

I think the reason is that at the end of the doLayout method in SwimLaneLayout.js, this.laneNames is reset to an empty array. Moreover, in the setupLanes method, it construct this.laneNames using this.network.vertexes. Therefore, the empty lanes are not includes in this.laneNames during the layout -re-rendering.

I can solve this issue by simply commenting out the line that resets this.laneNames. But I am wondering if there will be any unexpected consequences. I do not quite understand the comment of “clear our for next layout” either.

Please let me know if you need me to share some code to illustrate my issue. Looking forward to hearing from you.

Thanks for your time!

Min

Hmmm. It depends on whether one thinks the array of lane names (which in that particular sample are really the keys to the groups, not arbitrary strings associated with lanes/groups) should be generated automatically from the model and layout or whether it should be determined beforehand by the programmer.

Originally the layout was designed to be able to work even if there were no groups.

Being able to support empty lanes, though, clearly requires the ability to define the lanes without depending on the model data, since no nodes will have that “lane” property.

So I think your suggested solution is fine. Certainly for your purposes, go ahead and make that change to your copy of the SwimLaneLayout.js file (or are you using the TypeScript version?) that you had copied to your project.

Hi Walter, thanks for your confirmation.