Skip to main content

Selection

JointJS+ provides a Selection plugin that enables the ability to select elements on the paper.

Installation

import { ui } from '@joint/plus';

const selection = new ui.Selection({
paper: paper,
// optional, a custom collection that inherits from mvc.Collection
collection: new MyCollection
});
There is also a UMD version available

Include joint.ui.selection.js and joint.ui.selection.css in your HTML:

index.html
<link rel="stylesheet" type="text/css" href="joint.ui.selection.css">
<script src="joint.ui.selection.js"></script>

Access Selection through the joint.ui namespace:

index.js
const selection = new joint.ui.Selection({
paper: paper,
// optional, a custom collection that inherits from mvc.Collection
collection: new MyCollection
});

How does Selection work?

Selection implements elements selection, moving the selection in one go and manipulating the selection in terms of selecting/deselecting individual elements.

Usage

This section will guide you through the process of setting up the Selection plugin.

Initialize Selection

The Selection internally stores selected cells in a collection. This is a normal mvc 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.

const selection = new joint.ui.Selection({
paper: paper
});

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', (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', (elementView, evt) => {
if (evt.ctrlKey || evt.metaKey) {
this.selection.collection.remove(elementView.model);
}
});
note

The selection-box:pointerdown event is triggered on the selection view when the mouse cursor is pressed above a selected element.

Selection Collection

As our selection collection is just a normal mvc Collection, we can take advantage of the mvc methods.

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', () => {
// Print types of all the elements in the selection.
console.log(selection.collection.map((cell) => cell.get('type')));
});

Selection Example

This example combines the above snippets to create a simple selection mechanism. Users can click and hold while dragging to select multiple elements with a selection rectangle. Holding the CTRL key while clicking on an element will add/remove it from the selection depending on its current state.

Styling Selection

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:

Disabling Selection tools

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;
}

Customizing Selection tools

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:

In the example above, we added a new tool named myaction, positioned the tool to the south (bottom-center) and used our own icon represented as a base64. 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' });

Common Setup of the Selection in Applications Explained

The following is a common setup of the Selection in applications.

Cherry picking elements

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', (elementView, evt) => {
if (evt.ctrlKey || evt.metaKey) {
selection.collection.add(elementView.model);
}
});

Releasing selection on cherry-picked elements

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.

Initiating bulk selection

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', (evt) => {
if (evt.shiftKey) selection.startSelecting(evt);
});