documentationfor yFiles for HTML 3.0.0.1

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
selectableItemsclick, marquee, lasso, select allDetermines which types of graph items are selectable.
selectablePredicateclick, marquee, lasso, select allA predicate function that determines whether a given item should be selected.
clickSelectableItemsclickDetermines which types of graph items are selectable by click. Note that this is treated as a subset of selectableItems.
clickSelectablePredicateclickA predicate function that determines whether a given item should be selected by click.
marqueeSelectableItemsmarquee, lassoDetermines which types of graph items are marquee or lasso selectable.
marqueeSelectablePredicatemarquee, lassoA predicate function that determines whether a given item should be selected by marquee or lasso selection.

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.

Related events
Event Occurs when …​
GraphEditorInputMode.multi-selection-started…​ the selection state of one or more items is about to be changed as a result of a user interaction.
item-added / item-removed…​ the selection state of a graph item has changed.
GraphEditorInputMode.multi-selection-finished…​ the selection state of one or more items has been changed as a result of a user interaction.

  • 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 is null).
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:

selectionPolicy recognizers
Property Default Effect
nonenoneSelectionPolicy.REPLACE
extendSelectionRecognizerControlSelectionPolicy.EXTEND
subtractSelectionRecognizerShift ⇧SelectionPolicy.SUBTRACT
toggleSelectionRecognizerAltSelectionPolicy.TOGGLE

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:

Related events
Event Occurs when …​
drag-starting…​ a drag gesture is recognized, before the input mode is initialized for dragging.
drag-started…​ a drag gesture is recognized, after the input mode is initialized for dragging.
dragging…​ the pointer moves during drag operations and before the actual drag is performed.
dragged…​ the pointer moves during drag operations and after the actual drag is performed.
drag-canceling…​ the drag gesture is canceled before the input mode has been cleaned up.
drag-canceled…​ the drag gesture is canceled after the input mode has been cleaned up.
drag-finishing…​ a drag gesture has ended successfully before the actual drag operations have been finished.
drag-finished…​ a drag gesture has ended successfully after the actual drag operations have been finished.

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:

Custom marquee selection rectangle
customizing interaction marquee rectangle painter

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 is null).
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.

Customizing the lasso selection
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:

Custom lasso visualization
customizing interaction lasso 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