Selection
General
The selected items are managed by the IGraphSelection instance found in the GraphComponent's selection property. The IGraphSelection provides IObservableCollection<T> instances for nodes, labels, edges, ports, and bends and acts as a composite of those instances.
To select an item, add it to the IGraphSelection instance or the corresponding property matching the item’s type. Removing an item from those IObservableCollection<T>s deselects it.
An item is selected if it is contained in the IObservableCollection<T>s.
Interactive selection of graph items is supported by both GraphEditorInputMode and GraphViewerInputMode. Both provide access to the selection they manage through the property graphSelection. This is the same instance found in the selection property of the GraphComponent managed by these input modes.
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, SelectionPolicy).
GraphEditorInputMode and GraphViewerInputMode support four ways to select elements interactively:
selection by click, marquee selection, lasso selection, and the
select all command.
The items that can be selected by these methods can be
defined using the properties ending with SelectableItems
.
These properties define the item types that can be selected using a combination
of the values defined in GraphItemTypes.
yFiles for HTML supports different pointer types: mouse, touch, and stylus. For better readability, the term "click" includes mouse and stylus clicks and touch taps.
You can achieve finer control by changing the properties ending with SelectablePredicate
:
Member | Interaction | Description |
---|---|---|
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. Additionally, click selection is only handled for items which are clickable, see section Customizing Pointer Handling.
IGraphSelection dispatches events for each item whose selection state changes, specifically the item-added and item-removed events. On a higher level, both GraphEditorInputMode and GraphViewerInputMode dispatch events at the beginning and the end of a user interaction that changes the selection state of one or more graph items: multi-selection-started and multi-selection-finished. Despite their names, these events are also dispatched when the state of only one item changes.
Event | Occurs when … |
---|---|
- The item-added and item-removed events are also dispatched upon programmatic selection changes.
- For each affected item, one item-added or item-removed event is dispatched, even if the changes happen in one method call or during a single interaction.
- For user interaction driven changes, all item-added and item-removed events are dispatched between a multi-selection-started and a multi-selection-finished event.
You can further customize click selection by modifying the click handling as discussed in section Customizing Pointer Handling.
You can customize the visual indications of selected elements 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 for customization by changing the recognizers for some gestures. This can be important to avoid conflicts with input modes that share the same gesture (i.e., dragging on an empty canvas), e.g., MoveViewportInputMode.
The following recognizers are used:
- validBeginRecognizer
- An event recognizer that returns
true
if it is valid to begin a marquee selection at the given location. This also activates the validBeginCursor if one is set (the default isnull
). - beginRecognizer
- beginRecognizerTouch
- An event recognizer that returns
true
if the given event should be recognized as a pointer-down gesture that might start a marquee selection. - moveRecognizer
- moveRecognizerTouch
- An event recognizer that 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. - finishRecognizer
- finishRecognizerTouch
- An event recognizer that returns
true
if the given event should be recognized as a valid gesture to successfully finish the marquee selection.
GraphViewerInputMode and GraphEditorInputMode have different recognizers for marquee selection, and in GraphViewerInputMode, MarqueeSelectionInputMode is disabled by default.
During the drag gesture, different modifier keys can be used to change the current selectionPolicy. The following table lists the event recognizer properties used to detect the current policy, the default modifier key for those recognizers, and the chosen selectionPolicy:
Property | Default | Effect |
---|---|---|
When the selectionPolicy changes, the corresponding extendSelectionCursor, subtractSelectionCursor, or toggleSelectionCursor is used if it isn’t null
(which is the default). The marqueeCursor is used as a fallback.
Furthermore, MarqueeSelectionInputMode dispatches a sequence of events during the marquee gesture:
Event | Occurs when … |
---|---|
The MarqueeSelectionInputMode doesn’t change the selection itself. Instead, the GraphEditorInputMode and GraphViewerInputMode listen to its drag-finished event and handle it in their onMarqueeSelect method (or onLassoSelect if a custom CanvasComponent.projection is set).
The visualization of the marquee rectangle can be customized by setting a custom
IObjectRenderer<TRenderTag> to MarqueeSelectionInputMode’s marqueeRenderer property. If only the fill or stroke of the marquee rectangle should be adjusted, it is recommended to use CSS styling instead as explained in CSS Styling of Marquee Rectangle:
.yfiles-marquee-rect-template {
fill: #ff0000b0;
stroke: red;
stroke-dasharray: 1.5, 1.5;
}
Above example results in the following marquee selection rectangle:

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 is important 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 pointer. The gesture finishes after releasing the pointer, 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 freehand and straight segments. It is also possible to configure the input mode to finish only when the gesture ends in an area around the start point of the path.
- validBeginRecognizer
- An event recognizer which returns
true
if it is valid to begin a lasso selection at the given location. This also activates the validBeginCursor if any is set (default isnull
). - beginRecognizer
- beginRecognizerTouch
- event recognizers that determine when to start the gesture.
- dragFreeHandRecognizer
- dragFreeHandRecognizerTouch
- event recognizers which determine when to perform a freehand drag.
- startSegmentRecognizer
- startSegmentRecognizerTouch
- endSegmentRecognizer
- endSegmentRecognizerTouch
- event recognizers that determine when and how to switch from free drawing mode to segment mode.
- dragSegmentRecognizer
- dragSegmentRecognizerTouch
- event recognizer which determines when to draw a segment.
- finishRecognizer
- finishRecognizerTouch
- event recognizers which determine when to end the gesture.
- finishRegionRecognizer
- finishRegionRecognizerTouch
- finishRadius
- event recognizers which determine when to end the gesture within a defined radius from the starting point and the radius itself.
When the pointer is inside the finishRadius, the validEndCursor is used.
GraphViewerInputMode and GraphEditorInputMode have different recognizers for lasso selection. In both cases, 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.dragFreeHandRecognizer = EventRecognizers.MOUSE_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 = (eventSource, evt) =>
EventRecognizers.MOUSE_LEFT_DOWN(eventSource, evt) ||
EventRecognizers.MOUSE_LEFT_UP(eventSource, evt)
lassoSelectionInputMode.dragSegmentRecognizer = EventRecognizers.MOUSE_DRAG
// outside the finish radius finish only with double click
lassoSelectionInputMode.finishRecognizer =
EventRecognizers.MOUSE_LEFT_DOUBLE_CLICK
// or finish within the finish radius around the start point
lassoSelectionInputMode.finishRadius = 10
const lassoSelectionInputMode = graphEditorInputMode.lassoSelectionInputMode
lassoSelectionInputMode.dragFreeHandRecognizer = EventRecognizers.MOUSE_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 = (
eventSource: any,
evt: EventArgs
) =>
EventRecognizers.MOUSE_LEFT_DOWN(eventSource, evt) ||
EventRecognizers.MOUSE_LEFT_UP(eventSource, evt)
lassoSelectionInputMode.dragSegmentRecognizer = EventRecognizers.MOUSE_DRAG
// outside the finish radius finish only with double click
lassoSelectionInputMode.finishRecognizer =
EventRecognizers.MOUSE_LEFT_DOUBLE_CLICK
// or finish within the finish radius around the start point
lassoSelectionInputMode.finishRadius = 10
Note that the gesture can now only be ended in one of two ways. The first option is a double click, which automatically closes the path by drawing a straight segment between the current location and the start of the path. The second option is to end a segment within the finishRadius around its start point.
It is also possible to mix the freehand and 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 can now 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 =
EventRecognizers.MOUSE_LEFT_UP
// outside the finish radius finish only with double click
lassoSelectionInputMode.finishRecognizer =
EventRecognizers.MOUSE_LEFT_DOUBLE_CLICK
// or finish within the finish radius around the start point
lassoSelectionInputMode.finishRadius = 10
During the drag gesture, LassoSelectionInputMode supports changing the selectionPolicy and dispatches a sequence of events analogous to the MarqueeSelectionInputMode. The details about detecting the policy and the dispatched events are explained in the corresponding sections for Marquee selection.
The LassoSelectionInputMode doesn’t change the selection itself. Instead, the GraphEditorInputMode and GraphViewerInputMode listen to its drag-finished event and handle it in their onLassoSelect method.
The visualization of the region uses an outline in --yfiles-theme-secondary
and a half-transparent fill using the --yfiles-theme-secondary
as explained in Effects on Lasso and Marquee.
During the gesture, LassoSelectionInputMode can display an indicator for the region around the start location
where the lasso gesture can be finished.
The default circular visualization can be configured with the CSS class yfiles-lasso-finish-region
.
For full control an individual visualization can be set via the
finishRegionRenderer property.
function configureLassoRenderer(graphEditorInputMode) {
const lassoSelectionInputMode = graphEditorInputMode.lassoSelectionInputMode
lassoSelectionInputMode.finishRegionRenderer = new FinishRegionRenderer()
lassoSelectionInputMode.finishRadius = 10
}
class FinishRegionRenderer extends ObjectRendererBase {
createVisual(context, renderTag) {
if (renderTag.pathState == LassoPathState.STARTING) {
// do not show the finish rectangle when the user just started dragging
return new SvgVisualGroup()
}
const visualGroup = new SvgVisualGroup()
// add a rectangle with a red border
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('stroke-width', '3')
rect.setAttribute('fill', 'none')
rect.width.baseVal.value = 2 * renderTag.finishRadius
rect.height.baseVal.value = 2 * renderTag.finishRadius
visualGroup.add(new SvgVisual(rect))
this.setTransform(context, renderTag, visualGroup, rect)
return visualGroup
}
updateVisual(context, oldVisual, renderTag) {
if (renderTag.pathState == LassoPathState.STARTING) {
// do not show the finish rectangle when the user just started dragging
return oldVisual
}
if (oldVisual.children.size === 0) {
return this.createVisual(context, renderTag)
}
this.setTransform(
context,
renderTag,
oldVisual,
oldVisual.children.get(0).svgElement
)
return oldVisual
}
setTransform(context, renderTag, container, rectangle) {
container.transform = context.viewTransform
const viewLocation = context.canvasComponent.worldToViewCoordinates(
renderTag.location
)
const radius = renderTag.finishRadius
SvgVisual.setTranslate(
rectangle,
viewLocation.x - radius,
viewLocation.y - radius
)
}
}
function configureLassoRenderer(graphEditorInputMode: GraphEditorInputMode) {
const lassoSelectionInputMode = graphEditorInputMode.lassoSelectionInputMode
lassoSelectionInputMode.finishRegionRenderer = new FinishRegionRenderer()
lassoSelectionInputMode.finishRadius = 10
}
class FinishRegionRenderer extends ObjectRendererBase<
LassoPathFinishRegionRenderTag,
SvgVisualGroup
> {
protected createVisual(
context: IRenderContext,
renderTag: LassoPathFinishRegionRenderTag
): SvgVisualGroup | null {
if (renderTag.pathState == LassoPathState.STARTING) {
// do not show the finish rectangle when the user just started dragging
return new SvgVisualGroup()
}
const visualGroup = new SvgVisualGroup()
// add a rectangle with a red border
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('stroke', 'darkred')
rect.setAttribute('stroke-width', '3')
rect.setAttribute('fill', 'none')
rect.width.baseVal.value = 2 * renderTag.finishRadius
rect.height.baseVal.value = 2 * renderTag.finishRadius
visualGroup.add(new SvgVisual(rect))
this.setTransform(context, renderTag, visualGroup, rect)
return visualGroup
}
protected updateVisual(
context: IRenderContext,
oldVisual: SvgVisualGroup,
renderTag: LassoPathFinishRegionRenderTag
): SvgVisualGroup | null {
if (renderTag.pathState == LassoPathState.STARTING) {
// do not show the finish rectangle when the user just started dragging
return oldVisual
}
if (oldVisual.children.size === 0) {
return this.createVisual(context, renderTag)
}
this.setTransform(
context,
renderTag,
oldVisual,
(oldVisual.children.get(0) as SvgVisual).svgElement as SVGRectElement
)
return oldVisual
}
setTransform(
context: IRenderContext,
renderTag: LassoPathFinishRegionRenderTag,
container: SvgVisualGroup,
rectangle: SVGRectElement
) {
container.transform = context.viewTransform
const viewLocation = context.canvasComponent.worldToViewCoordinates(
renderTag.location
)
const radius = renderTag.finishRadius
SvgVisual.setTranslate(
rectangle,
viewLocation.x - radius,
viewLocation.y - radius
)
}
}
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 simultaneously. Sometimes, you might want only one or no item to be selected at a time. To enable this "`single selection mode`," disable MarqueeSelectionInputMode and set 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, EXTEND_SELECTION_HIERARCHY_UP, and EXTEND_SELECTION_HIERARCHY_DOWN from navigationInputMode.availableCommands. You can find an example 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(Command.TOGGLE_ITEM_SELECTION)
geim.availableCommands.remove(Command.SELECT_ALL)
geim.navigationInputMode.availableCommands.remove(
Command.EXTEND_SELECTION_LEFT
)
geim.navigationInputMode.availableCommands.remove(Command.EXTEND_SELECTION_UP)
geim.navigationInputMode.availableCommands.remove(
Command.EXTEND_SELECTION_DOWN
)
geim.navigationInputMode.availableCommands.remove(
Command.EXTEND_SELECTION_RIGHT
)
geim.navigationInputMode.availableCommands.remove(
Command.EXTEND_SELECTION_HIERARCHY_UP
)
geim.navigationInputMode.availableCommands.remove(
Command.EXTEND_SELECTION_HIERARCHY_DOWN
)
// Disable selection of (possibly multiple) items
geim.pasteSelectableItems = GraphItemTypes.NONE