Selection
General
The selection state of items is maintained by the IGraphSelection instance found in GraphComponent’s selection property. The IGraphSelection provides ISelectionModel<T> instances for each type of graph items. It also allows querying and changing the selection state for each model item.
- Selection models available on IGraphSelection
- selectedNodes
- selectedLabels
- selectedEdges
- selectedPorts
- selectedBends
- ISelectionModel<T>s for the different types of graph items.
- Methods for querying and setting the selection state on
- isSelected(item: T): boolean
- Whether the given model item is selected.
- setSelected(item: T, selected: boolean): void
- Setting the selection state of the given item to selected (
true
) or unselected (false
). - clear(): void
- Set all model items maintained by the selection model to unselected.
Interactive selection of graph items is supported by both GraphEditorInputMode and GraphViewerInputMode. Both provide access to the selection they manage through property graphSelection. This is the same instance found in the selection property of the GraphComponent these input modes manage.
Both modes provide convenience methods to directly select or deselect a single item as well as all marquee-selectable items in a given area: setSelected(IModelItem, boolean) and marqueeSelect(Rect).
GraphEditorInputMode and GraphViewerInputMode support three ways of selecting elements interactively:
selection by mouse click or tap, marquee selection, and the
select all command.
The items which are handled by these kinds of selection can be
defined using the …SelectableItems
properties.
These properties define the item types which can be selected using a combination
of the values defined in GraphItemTypes.
Finer control can be achieved by overriding the should…Select
methods:
Member | Interaction | Description |
---|---|---|
Instead of overriding the shouldSelectItem method you can set a predicate function using the selectablePredicate property.
Note that an item is only selected if all conditions are met. For example, an item is only considered for click selection if its type is set in both selectableItems and clickSelectableItems. More, click selection is only handled for items which are clickable, see section Customizing Mouse Clicks.
IGraphSelection dispatches an event for each item whose selection state changes, the ItemSelectionChanged event. On a higher level, both GraphEditorInputMode and GraphViewerInputMode dispatch events at the beginning and the end of a user interaction which changes the selection state of one or more graph items: MultiSelectionStarted and MultiSelectionFinished. Despite their name these events are also dispatched when the state of only one item changes.
Event | Occurs when … |
---|---|
- The ItemSelectionChanged event is also dispatched upon programmatic selection changes.
- For each affected item one ItemSelectionChanged event is dispatched, even if the changes happen in one method call or upon one single interaction.
- For user interaction driven changes, all ItemSelectionChanged events are dispatched in between a MultiSelectionStarted and a MultiSelectionFinished event.
You can make further click selection customizations by modifying the click or touch handling as discussed in sections Customizing Mouse Clicks and Customizing Touch Gestures.
The highlighting visualization of selected elements themselves can be customized as described in section Styling Selection, Focus, and Highlight.
Marquee selection
For marquee selection GraphEditorInputMode and GraphViewerInputMode let their child input mode MarqueeSelectionInputMode handle the marquee rectangle. MarqueeSelectionInputMode allows customization by changing the recognizers for some gestures. This might be of importance to avoid conflicts with input modes which share the same gesture (i.e. dragging on an empty canvas), e.g. MoveViewportInputMode.
- pressedRecognizer
- An event recognizer which returns
true
if the given event should be recognized as a mouse down gesture that might start a marquee selection. - draggedRecognizer
- An event recognizer which returns
true
if the given event should be recognized as a drag gesture. This is only queried if the MarqueeSelectionInputMode is already activated by a previous gesture. - releasedRecognizer
- An event recognizer which returns
true
if the given event should be recognized as a valid gesture to successfully finish the marquee selection.
GraphViewerInputMode has different recognizers than GraphEditorInputMode for marquee selection and its MarqueeSelectionInputMode is disabled by default.
During the drag gesture MarqueeSelectionInputMode dispatches a sequence of events:
Event | Occurs when … |
---|---|
The visualization of the marquee rectangle can be customized by setting a custom IVisualTemplate to MarqueeSelectionInputMode’s template property or by registering a custom IVisualTemplate with the resource keyMARQUEE_RECTANGLE_TEMPLATE_KEY.
Above example results in the following marquee selection rectangle:
You can set the cursor shown during dragging using the marqueeCursor property.
Lasso selection
Lasso selection in GraphEditorInputMode and GraphViewerInputMode is performed by their child input mode LassoSelectionInputMode, which handles drawing a path within which to select items. This child input mode is disabled by default, to avoid conflicting with marquee selection. LassoSelectionInputMode allows customization by changing the recognizers for some gestures. This might be of importance to avoid conflicts with input modes which share the same gesture (i.e. dragging on an empty canvas), e.g. MoveViewportInputMode.
By default, LassoSelectionInputMode is configured to draw the path around the selection area in a freehand gesture while dragging the mouse with the left mouse button held down. The gesture is finished after releasing the mouse button and the path is closed with a straight line from the current location to its start.
By changing one or more of its various event recognizers LassoSelectionInputMode can be configured to support a polyline path or a mixture of both freehand and straight segments. Also, it is possible to configure the input mode to finish only when the gesture is ended in an area around the start point of the path.
- prepareRecognizer
- prepareRecognizerTouch
- event recognizers that determine when to start the gesture.
- dragFreeRecognizer
- event recognizer which determines when to perform a freehand drag.
- finishRecognizer
- finishRecognizerTouch
- event recognizers which determine when to end the gesture.
- startSegmentRecognizer
- endSegmentRecognizer
- event recognizers that determine when and how to switch from free drawing mode to segment mode.
- dragSegmentRecognizer
- event recognizer which determines when to draw a segment.
- finishRegionRecognizer
- finishRegionRecognizerTouch
- finishRadius
- event recognizers which determine when to end the gesture within a defined radius from the starting point and the radius itself.
GraphViewerInputMode has different recognizers than GraphEditorInputMode for lasso selection and its LassoSelectionInputMode is disabled by default.
The following settings configure LassoSelectionInputMode to support a polyline lasso, i.e. a path consisting of straight segments:
const lassoSelectionInputMode = graphEditorInputMode.lassoSelectionInputMode
lassoSelectionInputMode.dragFreeRecognizer = MouseEventRecognizers.DRAG
// start a segment immediately at the beginning of the gesture or after the last segment is ended
lassoSelectionInputMode.startSegmentRecognizer = EventRecognizers.ALWAYS
// end a segment when the mouse button is pressed or released
lassoSelectionInputMode.endSegmentRecognizer = EventRecognizers.createOrRecognizer(
MouseEventRecognizers.LEFT_CLICK,
MouseEventRecognizers.LEFT_UP
)
lassoSelectionInputMode.dragSegmentRecognizer = MouseEventRecognizers.MOVE_OR_DRAG
// outside the finish radius finish only with double click
lassoSelectionInputMode.finishRecognizer = MouseEventRecognizers.LEFT_DOUBLE_CLICK
// or finish within the finish radius around the start point
lassoSelectionInputMode.finishRadius = 10
Note that the gesture now can only be ended by either a double click where the path is closed automatically by drawing a straight segment between the current location and the start of the path or by ending a segment with in the finishRadius around its start point.
It is also possible to mix the freehand and the polyline gestures. The following settings configure LassoSelectionInputMode to draw a freehand path while dragging the mouse with the left button down and straight segments when the button is released. Similar to the freehand configuration the gesture now can only be finished with a double click or by pressing or releasing the mouse button within the finishRadius around its start point.
const lassoSelectionInputMode = graphEditorInputMode.lassoSelectionInputMode
// start a segment when the mouse button is released
lassoSelectionInputMode.startSegmentRecognizer = MouseEventRecognizers.LEFT_UP
// outside the finish radius finish only with double click
lassoSelectionInputMode.finishRecognizer = MouseEventRecognizers.LEFT_DOUBLE_CLICK
// or finish within the finish radius around the start point
lassoSelectionInputMode.finishRadius = 10
During the drag gesture LassoSelectionInputMode dispatches a sequence of events:
Event | Occurs when … |
---|---|
The visualization of the path can be customized by setting the stroke and fill properties or by registering a custom Stroke or Fill with the resource keysLASSO_STROKE_KEY and LASSO_FILL_KEY.
During the gesture LassoSelectionInputMode can display an indicator for the region around the start location where the lasso gesture can be finished. Per default this indicator isn’t used but can be set via finishRegionTemplate or FINISH_REGION_TEMPLATE_KEY. When entering this region a highlight indicator is used to indicate that the gesture can now be finished. The visualization for this can be changed via finishRegionHighlightTemplate or FINISH_REGION_HIGHLIGHT_TEMPLATE_KEY.
// Set a custom stroke and fill
lassoSelectionInputMode.stroke = new Stroke({
fill: Fill.RED,
dashStyle: new DashStyle([2, 4], 1)
})
lassoSelectionInputMode.fill = new SolidColorFill(255, 0, 0, 65)
// Set a custom finish region visualization
lassoSelectionInputMode.finishRegionTemplate = new (class extends BaseClass(IVisualTemplate) {
/**
* @param {!IRenderContext} context
* @param {!Rect} bounds
* @param {*} dataObject
* @returns {?SvgVisual}
*/
createVisual(context, bounds, dataObject) {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke-width', '3')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('fill', 'none')
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return new SvgVisual(rect)
}
/**
* @param {!IRenderContext} context
* @param {!SvgVisual} oldVisual
* @param {!Rect} bounds
* @param {*} dataObject
* @returns {?SvgVisual}
*/
updateVisual(context, oldVisual, bounds, dataObject) {
const rect = oldVisual.svgElement
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return oldVisual
}
})()
// Set a custom finish region highlight visualization
lassoSelectionInputMode.finishRegionHighlightTemplate = new (class extends BaseClass(IVisualTemplate) {
/**
* @param {!IRenderContext} context
* @param {!Rect} bounds
* @param {*} dataObject
* @returns {?SvgVisual}
*/
createVisual(context, bounds, dataObject) {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('fill', 'none')
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return new SvgVisual(rect)
}
/**
* @param {!IRenderContext} context
* @param {!SvgVisual} oldVisual
* @param {!Rect} bounds
* @param {*} dataObject
* @returns {?SvgVisual}
*/
updateVisual(context, oldVisual, bounds, dataObject) {
const rect = oldVisual.svgElement
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return oldVisual
}
})()
// Set a custom stroke and fill
lassoSelectionInputMode.stroke = new Stroke({
fill: Fill.RED,
dashStyle: new DashStyle([2, 4], 1)
})
lassoSelectionInputMode.fill = new SolidColorFill(255, 0, 0, 65)
// Set a custom finish region visualization
lassoSelectionInputMode.finishRegionTemplate = new (class extends BaseClass(IVisualTemplate) {
createVisual(context: IRenderContext, bounds: Rect, dataObject: any): SvgVisual | null {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke-width', '3')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('fill', 'none')
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return new SvgVisual(rect)
}
updateVisual(context: IRenderContext, oldVisual: SvgVisual, bounds: Rect, dataObject: any): SvgVisual | null {
const rect = oldVisual.svgElement as SVGRectElement
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return oldVisual
}
})()
// Set a custom finish region highlight visualization
lassoSelectionInputMode.finishRegionHighlightTemplate = new (class extends BaseClass(IVisualTemplate) {
createVisual(context: IRenderContext, bounds: Rect, dataObject: any): SvgVisual | null {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('fill', 'none')
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return new SvgVisual(rect)
}
updateVisual(context: IRenderContext, oldVisual: SvgVisual, bounds: Rect, dataObject: any): SvgVisual | null {
const rect = oldVisual.svgElement as SVGRectElement
rect.x.baseVal.value = bounds.x
rect.y.baseVal.value = bounds.y
rect.width.baseVal.value = bounds.width
rect.height.baseVal.value = bounds.height
return oldVisual
}
})()
Above example results in the following lasso selection visualization:
You can set the cursor shown during dragging using the lassoCursor property.
Single Item Selection
All interactive selection gestures support selecting multiple items at the same time. Sometimes, one wants only one or no item to be selected at once. In order to enable this “single selection mode” disable MarqueeSelectionInputMode and the multiSelectionRecognizer to NEVER. Then remove SELECT_ALL and TOGGLE_ITEM_SELECTION from availableCommands and EXTEND_SELECTION_LEFT, EXTEND_SELECTION_RIGHT, EXTEND_SELECTION_UP, EXTEND_SELECTION_DOWN, SELECT_TO_PAGE_UP, and SELECT_TO_PAGE_DOWN from navigationInputMode.availableCommands. An example can be found in Single Selection.
// disable marquee selection
geim.marqueeSelectionInputMode.enabled = false
// disable multi selection with Ctrl-Click
geim.multiSelectionRecognizer = EventRecognizers.NEVER
// deactivate commands which can lead to multi selection
geim.availableCommands.remove(ICommand.TOGGLE_ITEM_SELECTION)
geim.availableCommands.remove(ICommand.SELECT_ALL)
geim.navigationInputMode.availableCommands.remove(ICommand.EXTEND_SELECTION_LEFT)
geim.navigationInputMode.availableCommands.remove(ICommand.EXTEND_SELECTION_UP)
geim.navigationInputMode.availableCommands.remove(ICommand.EXTEND_SELECTION_DOWN)
geim.navigationInputMode.availableCommands.remove(ICommand.EXTEND_SELECTION_RIGHT)
// Disable selection of (possibly multiple) items
geim.pasteSelectableItems = GraphItemTypes.NONE