Groups
Groups act as a container for zero or more nodes or other groups. In the UI, these can be collapsed, and edges to/from the nodes/groups inside the group are then temporarily relocated to the group container. There is no limit imposed on how deeply groups may be nested.
Groups have in common with nodes, edges and ports the two concepts of id
and of type
, and as with the other graph objects, type
will be set to "default"
if it cannot be determined. Group IDs and types either follow the default rules (ie. they are given by the id
and type
parameters, respectively, in the group's data), or they are derived by applying the current idFunction
and typeFunction
.
Groups, as with the other graph objects, can have arbitrary JSON data associated with them.
Rendering
As shown in the various examples at the start of this page, groups are rendered using client side templates just as nodes are. They are declared inside a view alongside nodes, edges and ports, and broadly follow the same syntax as node definitions - but there are a number of extra flags that can be set on a group definition.
A simple example to start:
toolkit.render({
...
view:{
nodes:{
"default":{
templateId:"tmplNode",
events:{
click:function(p) {
alert("You clicked on node " + p.node.id);
}
}
}
},
groups:{
"groupType1":{
templateId:"tmplGroupType1",
constrain:true
}
}
}
});
Here we declare that member of groups of type groupType1
are constrained to the group element (that is, they cannot be dragged outside of the group's bounds).
There are a number of flags available to control the drag behaviour of members of a group:
Flag | Description | Default |
droppable | Indicates that nodes/groups may be dropped onto the group, either from some other group or from the main canvas. |
|
constrain | Indicates nodes/groups may be dragged outside of the bounds of the group. When you do drag a node/group outside of the bounds of its parent, what happens next depends on the other flags you have set and where you have dropped it. `orphan:true`, for instance, will cause the node/group to be removed from its parent group. `revert` will reinstate the node/group's position inside its parent, unless it was dropped on another group. |
|
revert | Indicates a node/group dragged outside of its parent group will, unless dropped on another group, revert back to its position inside the group. |
|
prune | If true, Nodes dropped outside of the Group (and not dropped onto another Group) are removed from the dataset (not just the Group...the entire dataset). |
|
orphan | If true, nodes/groups dropped outside of the group (and not dropped onto another group) are removed from the group (but remain in the dataset). When you set this to `true`, `revert` is automatically forced to `false`. |
|
dropOverride | If true, nodes dropped onto other groups first have any rules established by this group applied. For instance, if the groups state `prune:true`, then the node would be removed from the dataset rather than be dropped onto another group. |
|
autoGrow | When `autoGrow` is switched on a group will grow in size to ensure that its child elements are all contained. Events that can cause a resize event include dropping of a node/group onto the group and also dragging a child element so that it intersects the boundary of a group. `autoGrow` will allow the size of a group to grow indefinitely unless a `maxSize` is set. |
|
autoShrink | When `autoShrink` is switched on a group will shrink in size such that the child elements are contained by the group, taking into account any `padding` that may be set. A shrink event may be instigated by dragging a child element or deletion of a child element. `autoShrink` will allow the size of a group to shrink indefinitely unless a `minSize` is set. Groups may shrink from their left or top edge as well as from their right or bottom edge. If you do not want this behaviour, set `allowShrinkFromOrigin` to false. |
|
autoSize | When true, switches on both `autoGrow` and `autoShrink`. |
|
minSize | When this is provided, the auto size routine will ensure that the group size never falls below the values provided in this object. |
|
maxSize | When this is provided, the auto size routine will ensure that the group size never goes above the values provided in this object. |
|
elastic | An `elastic` group is one in which auto sizing is switched on, and the size of the group adapts to the position and size of the child elements it contains. When you drag a child element in an elastic group, the group will grow and shrink such that it always encloses the child elements, taking into account any `padding` that may be set. Read about elastic groups [in full below](#elastic-groups). |
|
allowShrinkFromOrigin | When `autoShrink`, `autoSize` or `elastic` is set, a group may at times shrink in size from the left and/or top edge. Set `allowShrinkFromOrigin` to false to disable this behaviour. You can also invoke this behaviour at drag time by holding down the Ctrl or Meta key (on a mac that's the Command key). For elastic groups, `allowShrinkFromOrigin` is set to false by default, and can be invoked by holding down the Ctrl or Meta key during drag. |
|
elementsDraggable | Indicates child members of the group may be dragged. Set this to false to prevent child members from being draggable. |
|
Collapsing/Expanding Groups
You can collapse/expand a group using the collapseGroup
and expandGroup
methods on the Surface
widget. When you collapse a group, any edges from any of the member nodes/groups in the group to nodes/groups outside of the group are relocated to the group's container, and a CSS class is applied to the group's container, indicating the collapsed state. When you subsequently expand the group, the edges are placed back onto their appropriate nodes/groups.
It is important to note that when a group is collapsed, JsPlumb does not hide the member nodes/groups automatically for you. But a CSS class of jtk-group-collapsed
is added to the group's container, for you to handle this in your CSS.
The endpoint and anchor to be used in the collapsed state can be specified in the group definition in the view
:
import { BlankEndpoint, AnchorLocations } from "@jsplumbtoolkit/browser-ui"
toolkit.render({
...
view:{
groups:{
"groupType1":{
templateId:"tmplGroupType1",
endpoint:BlankEndpoint.type,
anchor:AnchorLocations.Continuous
}
}
}
...
});
Any valid anchor/endpoint (including custom endpoints) can be used here.
Magnetizing a collapsed/expanded Group
By default, the surface widget will run the Magnetizer whenever a group is collapsed or expanded: when a group is expanded, surrounding elements are adjusted so as to ensure the group does not intersect with any other element. When a group is collapsed, the rest of the elements in the view are gathered in towards the collapsed group. This behaviour can be switched off - see the afterGroupChange
flag in the Surface widget magnetizer options
Templating
Specifying the canvas
It is not necessarily the case that you wish to use your entire group template as the parent of the group's members. You can set a data-jtk-group-content
attribute on the element that you wish to have acting as the parent for the members (you might have noticed this in the examples above):
<script type="jtk" id="tmplMyGroup">
<div class="aGroup">
<h1>{{title}}</h1>
<div data-jtk-group-content="true" class="aGroupInner">
<!-- Child elements go here -->
</div>
</div>
</script>
Whenever a group is resized by the auto sizing code in the surface, the surface looks for an element in the group with this attribute, and if found, this is the element to which the surface applies the change of size. Otherwise the size is applied to the group's main element. Keep this in mind from a CSS perspective: your CSS should allow the size of the content area to mandate the size of its parent. Scroll/auto overflow is not supported inside a group element.
Autosizing Groups
Groups can be configured to automatically resize themselves to encompass the extents of their child nodes/groups, via the autoSize
flag on a group definition in a view:
{
groups:{
"groupType1":{
...
autoSize:true
...
},
"groupType2":{
...
autoSize:true,
maxSize:{w:600, h:600}
...
}
}
}
In this example, both group types are declared to auto size, but groupType2
will grow to a maximum of 600 pixels in each axis.
Autosizing is run after a data load or when data exists in a JsPlumb Toolkit instance and it is rendered to some surface.
You can run auto sizing on demand (on all groups):
surface.autoSizeGroups()
or on a single group:
surface.sizeGroupToFit(group:Group)
Layouts
By default, every group has an Absolute
layout assigned to it. If your node data has left
/top
properties in it, these values will automatically be used to place nodes/groups inside of their parent groups.
Specifying in the view
To specify the layout for a specific type of group, set it in that group's entry in your view:
{
...
groups:{
"someGroupType":{
...
layout:{
type:HierarchyLayout.type,
options:{
orientation:"vertical"
}
}
}
}
...
}
The format of the layout
parameter is identical to the layout
parameter in the root of the view
.
Layout on demand
You can force a layout in a group like this:
surface.relayoutGroup(group:string|Group)
This will cause a layout to be run immediately on the given group (which may be passed in as the group object, or just its id)
Ad-hoc group layout
You can run an ad-hoc layout on a group ay any time:
surface.adHocGroupLayout(group:string|Group, layoutParams:LayoutParameters)
This will cause the group's layout to be temporarily swapped out with a layout conforming to the spec you provide in layoutParams
, the ad-hoc layout will then be run, and the original group layout reinstated (but without running the original layout again of course!)
Relationship to group size
By default, a layout in a group will cause the auto size routine to be run for the group immediately afterwards.
Elastic groups
Elastic groups allow your users to dynamically resize a group by dragging its child elements around inside of it. To setup a group as elastic:
{
groups:{
default:{
elastic:true,
minSize:{ w:250, h:250 } // optional, but it does tend to help aesthetically to have a minSize.
}
}
}
Dragging elements out of an elastic group
To drag a child node out of an elastic group, hold down the Shift key prior to the drag (and hold it for the duration of the drag):
Resizing an elastic group from left/top
By default an elastic group (in fact any group) will not resize from the left and/or top edge. We call this "shrink from origin", and you can switch it on via a flag on a group definition:
{
groups:{
default:{
elastic:true,
allowShrinkFromOrigin:false,
minSize:{ w:250, h:250 } // optional, but it does tend to help aesthetically to have a minSize.
}
}
}
or on an ad-hoc basis by holding down the meta key (command on Macs) prior to the drag. In this video we first show the default behaviour, where the origin stays fixed, and then the effect of holding down Ctrl/Meta as a child vertex is being dragged.
Nested elastic groups
Elastic groups which are themselves children of another elastic group will relay size changes during dragging to their parent, so that the user can see what changes will be made to all the groups.