🎉 JointJS has new documentation! 🥳
Selection implements elements selection, moving the selection in one go and manipulating the selection in terms of selecting/deselecting individual elements.
Include joint.ui.selection.js
and joint.ui.selection.css
files to your HTML:
<link rel="stylesheet" type="text/css" href="joint.ui.selection.css">
<script src="joint.ui.selection.js"></script>
The Selection internally stores selected cells in a collection. This is a normal
Backbone Collection. It can be accessed via collection
attribute. This view takes care of rendering the bounding rectangle during the selection action, determining which elements fall into this rectangle and also provides methods for selecting/deselecting individual elements. The view also listens to the underlying collection and updates selection boxes when an element is removed/added/reset i.e. selection.collection.add(element);
finds the view for the element on the paper and render a selection box above it.
var selection = new joint.ui.Selection({
paper: paper,
collection: new MyCollection // optional, a custom collection that inherits from Backbone.Collection
});
The next step is to hook the selection actions to the relevant events triggered on the paper and selection:
// Initiate selecting when the user grabs the blank area of the paper.
paper.on('blank:pointerdown', selection.startSelecting);
// Select an element if CTRL/Meta key is pressed while the element is clicked.
paper.on('element:pointerup', function(cellView, evt) {
if (evt.ctrlKey || evt.metaKey) {
selection.collection.add(cellView.model);
}
});
// Unselect an element if the CTRL/Meta key is pressed while a selected element is clicked.
selection.on('selection-box:pointerdown', function(elementView, evt) {
if (evt.ctrlKey || evt.metaKey) {
this.selection.collection.remove(elementView.model);
}
});
Note that the selection-box:pointerdown
event is triggered on the selection view when
the mouse cursor is pressed above a selected element.
As our selection collection is just a normal Backbone Collection, we can take advantage of the Backbone methods. For instance:
To select an element.
selection.collection.add(element);
selection.collection.add(element, { silent: true }); // add element to the collection, but renders no selection box.
To deselect an element.
selection.collection.remove(element);
To deselect all elements.
selection.collection.reset([]);
To select multiple elements and deselect all the other elements.
selection.collection.reset([element1, element2]);
To identify elements that are currently in the selection.
selection.collection.on('reset add', function() {
// Print types of all the elements in the selection.
console.log(selection.collection.pluck('type'));
});
The bounding rectangle of the active selection, the rectangles above the selected elements and the rectangle around all the elements
once the selection is made can all be styled in CSS.
The selection bounding rectangle is a <div> element with the .joint-selection
class. The rectangles
above the selected elements are also <div> elements having the .selection-box
class and the final
rectangle surrounding all the selected element is a <div> with class .selection-wrapper
. An example of
a custom styling might look like the following:
.joint-selection {
background-color: red;
border: 2px dashed red;
opacity: .7;
}
.selection-box {
border: 1px solid #8e44ad;
margin-top: -4px;
margin-left: -4px;
box-shadow: 2px 2px 5px #8e44ad;
}
.selection-wrapper {
border: 1px dotted #8e44ad;
}
As you might have noticed, each selection is surrounded by a rectangle and offers three
built-in icon tools by default: remove
, rotate
and resize
.
To disable any of these tools you may add a line similar to the following to your css:
.joint-selection .handle.rotate { display: none; } /* disables the rotate tool */
Another way to remove tool handles is via JavaScript:
selection.removeHandle('rotate');
To quickly disable all the tools (hide them) and also to hide the rectangular box around all the selected elements, you can simply do:
.selection-wrapper { display: none; }
Selection provides three methods for adding, removing and changing custom tools: addHandle()
, removeHandle()
and changeHandle()
.
Use the addHandle()
method to add new tools to your selection:
selection.addHandle({ name: 'myaction', position: 's', icon: 'myaction.png' });
selection.on('action:myaction:pointerdown', function(evt) {
evt.stopPropagation();
alert('My custom action.');
});
In the example above, we added a new tool named myaction
, positioned the tool to the south (bottom-center)
and used our own icon myaction.png
. When the user clicks on our tool, Selection triggers an
event named action:[name]:pointerdown
. We can handle the event by listening
on the Selection object. Similarly, the Selection triggers action:[name]:pointermove
and
action:[name]:pointerup
events. This gives us a high flexibility in implementing
our own actions. You might have noticed that this API is exactly the same as in the ui.Halo plugin.
The difference is that in Selection, we can have actions that manipulate multiple elements in one go.
For removing a tool, use the removeHandle(name)
method:
selection.removeHandle('myaction');
changeHandle()
method allows us to change tools. For instance, if we want to change a
position of the remove tool, we could use:
selection.changeHandle('remove', { position: 'ne' });
paper | (required) The JointJS paper the Selection should operate on. |
---|---|
graph | The JointJS graph the Selection should operate on. If no graph is passed paper.model is used. |
collection | A Backbone Collection object used to
store selected cells. If no collection is passed new Backbone.Collection is used. |
filter | Either an array in which case it can contain (even intermixed) cells or
cell types that will be ignored by the selection. This is useful if you have
certain elements in the diagram that are not supposed to get selected. It can
also be function in which case it will be called with a cell as an argument
and should return true if that cell should be filtered out of the
selection. The function gives you more flexibility in deciding whether
an element can or cannot be selected. Example:
|
boxContent(cellView, boxDOMElement) | A function that returns an HTML string with the content that will be used in the information box below the selection. By default, the box shows the number of selected elements. |
useModelGeometry | If set to true , the cells position and dimensions will be used as a basis for the Selection wrapping rectangle position. By default, this is set
to false which causes the Selection wrapping rectangle position be based on the bounding box of the selected element views. Sometimes though,
your shapes can have certain SVG sub elements that stick outof the view and you don't want these sub elements to affect the Selection wrapping rectangle position. In this case, set the useModelGeometry to true .
|
strictSelection | If set to true , only elements that are fully contained in the selection rectangle will be selected as opposed to the
default behaviour that selects elements whose bounding box intersects the selection rectangle.
|
allowTranslate | If set to false , users are not allowed to move selected elements around by dragging selection boxes. It defaults to true . |
preserveAspectRatio | Set to true if you want the resizing to preserve the aspect ratio of the elements.
The default is false .
|
rotateAngleGrid | When selected elements are rotated the resulting angles are snapped to this value. It defaults to 15 degrees. |
handles | A array of objects defining the tools around the selection. This array defaults to:
Normally, you do not need to set this array. It's better to use the
addHandle() , removeHandle() and changeHandle()
methods described below in the API section.
|
translateConnectedLinks | When translating selected elements, should the connected links also be translated?
Based on the selected value of the ui.Selection.ConnectedLinksTranslation enumerator, the behavior is as follows:
ui.Selection.ConnectedLinksTranslation.ALL .
|
addHandle(opt) | Add a custom tool to the Selection. opt.name is
the name of the custom tool. This name will be also set as a CSS class to the
handle DOM element making it easy to select it your CSS stylesheet. opt.position
is a string that specifies a position of the tool handle. Possible values are
n , nw , w , sw , s ,
se , e and ne . opt.icon is
a URL of the icon used to render the tool. This icons is set as a background image on
the tool handle DOM element.
|
---|---|
removeHandle(name) | Remove a tool handle named name from the Selection.
|
changeHandle(name, opt) | Change a tool handle named name in the Selection. The opt object can contain the
same parameters as with the addHandle() method except of the name property.
opt parameters will be merged with those defined previously.
|
on(event, callback) | Register a handler (callback ) for an event See
the Selection Events section for the list of events
the Selection object triggers.
|
startSelecting(evt) | Initiate bulk selection. See below in the Common Setup section how that can be used. |
createSelectionBox(element) | Create a single selection box above an element. |
destroySelectionBox(element) | Destroy a single selection box, which is rendered above an element. |
The Selection object triggers events when the user manipulates its tools. These events can
be handled by using the Selection on()
method.
action:[name]:pointerdown | Triggered when the user clicks (touches) on a tool handle named [name] .
The handler is called with the mousedown event object, and x and y of the pointer in local coordinates.
|
---|---|
action:[name]:pointermove |
Triggered when the user moves with mouse cursor after a tool handle named [name]
was mousedowned (touched).
The handler is called with the mousemove event object, and x and y of the pointer in local coordinates.
|
action:[name]:pointerup |
Triggered when the user releases his mouse cursor after a tool handle named [name]
was mousedowned (touched).
The handler is called with the mouseup event object, and x and y of the pointer in local coordinates.
|
action:[name]:contextmenu | Triggered when the user invokes contextmenu on a tool handle named [name] .
The handler is called with the mousedown event object, and x and y of the pointer in local coordinates.
|
selection-box:pointerdown |
Triggered when the user starts interacting with a selected element, an element that has a selection box above it.
The handler gets passed the element view, the DOM event object, x and y paper local coordinates.
Use elementView.model if you wish to access the actual element model.
See below in the Common Setup section how that can be used.
|
selection-box:pointermove |
Triggered when the user is moving with a selected element, an element that has a selection box above it.
The handler gets passed the element view, the DOM event object, x and y paper local coordinates.
|
selection-box:pointerup |
Triggered when the user stops interacting with a selected element, an element that has a selection box above it.
The handler gets passed the element view, the DOM event object, x and y paper local coordinates.
|
The following is a common setup of the Selection in applications.
For cherry picking elements
- when the user clicks on an element holding
the [CTRL]
key, we register a handler for the cell:pointerup
event on the paper, which is
triggered when the user releases his mouse above a cell (either element or a link - links get filtered out in
our case). In this handler, we add the element to our selection collection and create a selection box around that element.
paper.on('element:pointerup', function(elementView, evt) {
if (evt.ctrlKey || evt.metaKey) {
selection.collection.add(elementView.model);
}
});
To implement the reverse action of cherry-picking, i.e. when the user clicks a selected
element while holding the [CTRL]
key, we register a handler for the
selection-box:pointerdown
event on the Selection (see Selection events for reference).
In this handler, we remove the element from our selection collection and destroy the selection box.
selection.on('selection-box:pointerdown', function(elementView, evt) {
if (evt.ctrlKey || evt.metaKey) {
selection.collection.remove(elementView.model);
}
});
Last thing we want to setup is the bulk selection that should happen when the user drags a blank area in the paper:
paper.on('blank:pointerdown', selection.startSelecting);
TIP: some applications might not want the user to be able to create selections
when dragging a blank area in the paper. This is because they might have a different
action for this, let's say panning the paper. In that case, you can,
for example, start bulk selection only when the [SHIFT]
key is being hold:
paper.on('blank:pointerdown', function(evt) {
if (evt.shiftKey) selection.startSelecting(evt);
});