Drag Contents to Resize Group is Slow

Hi,

This was an issue I asked in another thread, but creating a new one for it as you requested.

I have extended the SubprocessGroupTemplate in the BPMN extension example. I like the simple look and feel of the group node, using of the placement object and not allowing resizing of the group. I am using the CustomDraggingTool code and some other code sample you provided that highlights the group node on drop and drag of contents to cue the user as to whether the node is dropping and dragging in the group bounds. I also want my users to be able to regroup nodes and groups and be able to drag nodes in and out of groups.

Making computeBoundsAfterDrag to true allows the user to drag and drop between groups (as shown in the Regrouping example). The problem I’m facing and shows up also in the regrouping example is that the calculation of the group size is very tightly bound to the exact border of the group and the user has to really slowly move the node in order to resize the group. I cannot have the user use a special key with drag to regroup the node/group as shown in stayInGroup function.

I want the group to resize more leniently on dragging nodes to the edges. I will attach code sample and some screenshots that I hope help describe the issue.

Thanks a lot for the help.

Andrea


       function highlightGroup(e, grp, show) {
        if (!grp) return;
        e.handled = true;
        if (show) {
          // cannot depend on the grp.diagram.selection in the case of external drag-and-drops;
          // instead depend on the DraggingTool.draggedParts or .copiedParts
          var tool = grp.diagram.toolManager.draggingTool;
          var map = tool.draggedParts || tool.copiedParts;  // this is a Map
          // now we can check to see if the Group will accept membership of the dragged Parts
          if (grp.canAddMembers(map.toKeySet())) {
            grp.isHighlighted = true;
            return;
          }
        }
        grp.isHighlighted = false;
      }
  
      // Upon a drop onto a Group, we try to add the selection as members of the Group.
      // Upon a drop onto the background, or onto a top-level Node, make selection top-level.
      // If this is OK, we're done; otherwise we cancel the operation to rollback everything.
      function finishDrop(e, grp) {
       var ok = (grp !== null
                  ? grp.addMembers(grp.diagram.selection, true)
                  : e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
        if (!ok) e.diagram.currentTool.doCancel();
      }
 var subProcessGroupTemplate=
        $(go.Group, "Spot",
          {
            copyable: false,
            locationSpot: go.Spot.Center,
            locationObjectName: "PH",
           // resizable: true, resizeObjectName: "PH",
      		/*fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides, portId: "",            isSubGraphExpanded: true,            memberValidation: function (group, part) {
              return !(part instanceof go.Group) ||
                (part.category !== "Pool" && part.category !== "Lane");
            },*/
            mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
            mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
            computesBoundsAfterDrag: true,
            // when the selection is dropped into a Group, add the selected Parts into that Group;
            // if it fails, cancel the tool, rolling back any changes
            mouseDrop: finishDrop,
            handlesDragDropForMembers: true,  // don't need to define handlers on member Nodes and Links
            // Groups containing Groups lay out their members horizontally
            contextMenu: activityNodeMenu,
            itemTemplate: boundaryEventItemTemplate,
            selectionAdornmentTemplate:
          $(go.Adornment, "Auto",
            $(go.Shape, "RoundedRectangle",
            { fill: null, stroke: "#296796", strokeWidth: 1.5,
            strokeDashArray: [3,2] }),
            $(go.Placeholder)
          )
          },
          new go.Binding("background", "isHighlighted", function(h) {
            if(h) return "rgba(41,103,150)"; else return "transparent";}).ofObject(),
          new go.Binding("itemArray", "boundaryEventArray"),
        $(go.Panel, "Auto",
            $(go.Shape, "RoundedRectangle",
              {
                name: "PH", fill: "rgba(255,255,255, 0.8)", stroke: SubprocessNodeStroke,
                //portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
                //fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
              }, 
              new go.Binding("minSize", "isSubGraphExpanded", 
              function(s) {
                if(s){return new go.Size(200, 100);} 
                else {return new go.Size(ActivityNodeWidth, ActivityNodeHeight);}}).ofObject(),
              new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
            ),
            $(go.Panel, "Vertical",
              { defaultAlignment: go.Spot.TopLeft },
              $(go.TextBlock,  // label
                { margin: 3, editable: true },
                new go.Binding("text", "label").makeTwoWay(),
                new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
              // create a placeholder to represent the area where the contents of the group are
              $(go.Placeholder,
            { padding: new go.Margin(20, 20)},
              ),
              makeMarkerPanel(true, 1)  // sub-process,  loop, parallel, sequential, ad doc and compensation markers
            )  // end Vertical Panel
          )
        ); 

Are there any layouts in any of your templates or as the Diagram.layout? If so, you might want to set Layout.isRealtime to false on them.

But I’m just guessing what might be going on. It’s hard to tell from the description.

Hi,

The only layouts we use are on the swimlane (LayeredDigraph) and pool (GridLayout for the lanes). The subprocess here is not inside a pool/swimlane.

The same behavior can be demonstrated on the Regrouping example Regrouping Demo where if you drag groups to the edge of a parent the parent resizes, but only a few pixels at a time. It makes it easy to drag the group out, but also makes resizing slow. Is there a way to calculate the edge of the group with more margin for example?

Thanks.

Andrea

So you want the user to be able to resize a group by dragging its members, but you want to allow a drop that happens some distance outside of the group to stay within the group?

Doesn’t that depend on the size of the node that you are dragging? If you drag a large group, it’s easy to make its containing group much bigger.

Still, I think there are several possibilities for you to consider. First, you could control whether the dragged parts could leave the group at all by using a modifier such as the Shift key.

Second you could make finishDrop in the Regrouping sample smarter, by recognizing that the mouse drop point is just outside of the containing group, and then deciding not to change group membership. But you’ll need to handle the multiple-selection case where the selected nodes belong to different groups.