Selections
A selection is a collection of nodes, groups, ports and edges (zero or more of each), upon which operations can be made that affect the entire set at once.
You can work with these in one of two ways - either use the current selection associated with an instance of the Toolkit, or create an ad-hoc selection.
Current selection
Each instance of the toolkit maintains a current selection, exposing several methods for you to work with it. Changes to the current selection are propagated to all renderers registered on some instance of the toolkit.
The principal methods for working with the current selection are:
setSelection(obj)
Set the current selection. Here, obj
can take a number of forms:
- A node, group, port or edge object
- A list of nodes/groups/ports/edges
- Another selection
- A path
addToSelection(obj)
Add something to the current selection. Here, obj
can take a number of forms:
- A node, group, port or edge object
- A list of nodes/groups/ports/edges
- Another selection
- A path
addPathToSelection(params)
A helper method to get a path (see here) and add it to the current selection.
removeFromSelection(obj)
Remove something from the current selection. Valid values for obj
are the same as for the addToSelection
and setSelection
methods.
getSelection()
Get the current selection. This returns a Selection
, which is a selector-like object that offers a number of methods for performing operations on the selection as a whole.
- append append a new item to the current selection
- clear clear the current selection (same as calling
toolkit.clearSelection()
- each Iterate the selection. The required callback signature is
function(index, object)
. - eachEdge Iterate through only the edges in the selection.
- eachNode Iterate through only the nodes/ports in the selection.
- remove Remove the given item from the current selection.
clearSelection()
Clears the current selection. This method is analogous to calling getSelection().clear()
.
--
Selecting Descendants
If you are working with hierarchical data, you can use the Toolkit to get a list of descendants of some vertex (and, optionally, the edges to and from each vertex):
const descendants = toolkit.selectDescendants(someNode)
The return value is a Selection
, with all of the methods discussed above available. By default this selection does not include the focus node or any edges, but the method signature is as follows:
Home > @jsplumbtoolkit/browser-ui > JsPlumbToolkit > selectDescendants
JsPlumbToolkit.selectDescendants() method
Selects all descendants of some Node or Group, and, optionally, the Node/Group itself.
Signature:
selectDescendants(obj: string | Node | Group, includeFocus?: boolean, includeEdges?: boolean): Selection<Edge | Node | Group>;
Parameters
Parameter | Type | Description |
---|---|---|
obj | string | Node | Group | Node/Group, or ID of Node/Group, to select |
includeFocus | boolean | Whether or not to include the focus node/group in the returned dataset. Defaults to false. |
includeEdges | boolean | Whether or not to include edges in the returned dataset. Defaults to false. |
Returns:
So this call would return all of a vertex's descendants plus the vertex itself:
var descendants = toolkit.selectDescendants(someNode, true);
And this would get the descendants, the node itself, and any edges connecting the nodes in the set:
var descendants = toolkit.selectDescendants(someNode, true, true);
AdHoc selection
In addition to the current selection, you can also select a set of vertices and/or edges on an adhoc basis:
- select(obj)
- deselect(obj)
Here, obj
can be some node/group/port/edge, or the ID of some node, group or port, or an array of a combination of these.
Filtering objects
A more powerful method to use to get a set of objects is filter
, which, as the name suggests, can filter the contents of some Toolkit instance according to a few criteria. There are two ways to call this method.
Filtering with a function
You can pass a Function as argument to the filter
method, which is expected to return true to indicate that a given object should be included:
import { Node } from "@jsplumbtoolkit/browser-ui"
let selection = toolkit.filter((obj) => {
return (obj.objectType === Node.objectType)
})
Note here that this function is given every object managed by the Toolkit instance - meaning all groups, nodes and edges. So you can use objectType
to test if the object is a node or an edge. In this simple example we have simply returned all the nodes in the Toolkit instance.
Another example of using a function:
import { Node } from "@jsplumbtoolkit/browser-ui"
let selection = toolkit.filter((obj) => {
return obj.objType === Node.objectType && obj.data.maxValue < 150
});
Here we return only nodes whose maxValue
is less than 150.
Filtering with a match object
Alternatively, you can pass a match object in to the filter
method:
let selection = toolkit.filter({
maxValue:150
});
Here we've told the Toolkit we are interested only in vertices whose maxValue
is exactly 150. Note that with a match object only exact matches are supported: we cannot recreate the previous example in which vertices whose maxValue
was less than 150 are returned.
You can match an arbitrary number of values:
let selection = toolkit.filter({
maxValue:150,
lorem:"ipsum"
});
Here we get vertices with a maxValue
of 150 and a lorem
of "ipsum".
Partial matches with a match object
You can instruct the Toolkit that an object that matches at least one entry in the match object should be included in the output (by default, every value must match):
let selection = toolkit.filter({
maxValue:150,
lorem:"ipsum"
}, true)
...by passing in true
as the second argument to the filter
function. So in this example we now get vertices that have a maxValue
of 150 and/or a lorem
of "ipsum".
Selection mode
This concept, introduced in 6.2.0, allows you to control what can be added to the selection by its type - it's basically a higher level version of the filter
we just discussed.
There are 5 modes supported by a selection, of which the default is mixed
:
- SelectionModes.mixed Any combination of nodes, edges and groups is supported
- SelectionModes.isolated Only a set of nodes/groups, OR a set of edges, but not a mix. Conceptually this means the selection works in a "vertices only" or "edges only" mode, where the selection object decides which of these is appropriate when a new addition is made. For instance, if you have a selection in isolated mode that already has one node, then no new edges may be added. If you subsequently remove that node, making the selection empty, you could then add an edge.
- SelectionModes.nodesOnly Only nodes. No groups or edges.
- SelectionModes.groupsOnly Only groups. No nodes or edges.
- SelectionModes.edgesOnly Only nodes. No groups or nodes.
The mode for a selection can be set in its constructor:
const sel = new Selection(toolkitInstance, {
mode: SelectionModes.edgesOnly
})
or it can be set on an existing selection object:
mySelection.setMode(SelectionModes.isolated)
If you want to change the mode for the current selection of some Toolkit instance, you can do that programmatically:
myToolkitInstance.getSelection().setMode(SelectionModes.mixed)
Selecting objects with the mouse
The Surface operates in one of two modes:
- pan
The default mode, in which the mouse is used to pan the UI and support click events etc.
- select
In this mode, the mouse is used to select objects in the UI using click and drag ("lasso" selection). Holding down the Shift key while selecting causes new objects to be added to the current selection. Otherwise, each new click and drag operation causes the current selection to be replaced.
Lasso selection works in the same way as AutoCAD: selecting from left to right will add nodes that intersect, in any amount, with the current selected area. Selecting from right to left will add only nodes that are completely enclosed by the current selected area.
Select mode
By default, the lasso draws an element on screen that indicates the selected area:
You can also run the lasso in 'inverted' mode:
To do this, you must set a flag on the lasso plugin's options:
import { LassoPlugin } from "@jsplumbtoolkit/browser-ui"
toolkitInstance.render(someElement, {
..
plugins:[
{
type:LassoPlugin.type,
options:{
invert:true
}
}
]
...
});
Filtering lasso selections
You can provide a list of classes that indicate elements upon which a mousedown should not launch the lasso:
import { LassoPlugin } from "@jsplumbtoolkit/browser-ui"
toolkitInstance.render({
...
plugins:[
{
type:LassoPlugin.type,
options:{
filter: ".controls, .controls *, .miniview, .miniview *",
}
}
]
...
});
This example is from the Hierarchical layout demo that ships with the Toolkit.
Lasso CSS
In 'normal' mode, the element drawn on screen is given a class of jtk-lasso
. In 'inverted' mode, the elements drawn on screen (there are 4 - top, bottom, left and right) are given a class of jtk-lasso-mask
.
Removing everything in a selection
This is a fairly common use case when working with a selection:
let selection = toolkit.selectDescendants(someNode)
toolkit.remove(selection)
Here we used the selectDescendants
method, but we could have used any method that returns a selection or path - select
, selectDescendants
, filter
or getPath
.
Appending selections
You can append selections to each other:
let selection1 = toolkitInstance.select(["1", "2", "3"]);
// we have a selection containing nodes 1, 2 and 3
let selection2 = toolkitInstance.getPath({source:"1", target:"17"});
// we have a selection containing the path from node 1 to node 17
selection1.append(selection2);
This is perhaps a spurious example. But you get the idea.
Limiting selection size
You can limit the number of group, nodes and/or edges in a selection or Toolkit instance's currentSelection
. This can be useful in a few ways: maybe your app wants to enforce that only one node is selected at any point in time, for instance. Or maybe you want to maintain a selection queue of fixed size for some purpose.
Limiting the Toolkit's Current selection
You can provide constructor parameters to control this behaviour:
import { Selection, newInstance } from "@jsplumbtoolkit/browser-ui"
const tk = newInstance({
maxSelectedNodes:1,
maxSelectedGroups:1,
maxSelectedEdges:1,
selectionCapacityPolicy:Selection.DISCARD_NEW
});
Here we have specified that at most 1 node, 1 group and 1 edge may be selected, and that when the user tries to add a new node or edge to the current selection, it should be discarded. The other option - the default option - for selectionCapacityPolicy
is Selection.DISCARD_EXISTING
, which takes the 0th element from the underlying list.
You can also control these values with setter methods:
tk.setMaxSelectedNodes(4)
tk.setMaxSelectedGroups(3)
tk.setMaxSelectedEdges(3)
tk.setSelectionCapacityPolicy(Selection.DISCARD_EXISTING)
Limiting an AdHoc selection
To set limits and control the capacity policy of an ad-hoc selection, these methods are available:
var sel = tk.select() // create an empty selection
sel.setMaxNodes(4)
sel.setMaxEdges(3)
sel.setCapacityPolicy(Selection.DISCARD_EXISTING);
Hiding/Showing selections
Once you have a selection, you can instruct a surface to hide/show the entire selection at once:
var sel = tk.select(["node1", "node2"]);
surface.setVisible(sel, false);
Here we assume the existence of a Toolkit called tk
and a Surface called surface
.