Moving Items
Moving graph items is handled by GraphEditorInputMode which delegates most of the work to its child input modes MoveInputMode in general and MoveLabelInputMode for labels in particular. The types of items that can be moved are defined by the movableItems property.
Some general customization options such as configurable properties are presented in section Moving Items. Moving labels is explained in a separate section below.
Moving items in general is handled by MoveInputMode. Some items such as bends or ports, however, are instead moved with a special IHandle, managed by HandleInputMode. Note that actually customizing the results of the gesture works the same in either case, as described below.
The items which are involved in the moving operation can be retrieved from property affectedItems. All events below are dispatched at a time where the affectedItems are valid, therefore it is safe to access it in event handlers for these events to determine the moved items.
Event | Occurs when… |
---|---|
If you want to be informed about a completed move operation, you can listen for DragFinished events.
The actual moving of the graph items is performed by a so-called position handler, modeled by implementations of the IPositionHandler interface. IPositionHandlers are similar to handles and both actually inherit the same parent interface. The implementation of an IPositionHandler is responsible for actually moving the item.
The default IPositionHandler is a composite handler which collects all movable item’s position handlers (and handles) from the item’s lookup. Modifying the lookup to return a custom position handler can be a means to further customize the move behavior. E.g., modifying a node’s lookup to hide the position handler prevents the node from being moved:
In many cases wrapping the existing implementation is a good way of customizing movement of graph items, as shown below in Register a custom position handler as wrapper.
IPositionHandler uses four methods to maintain its life cycle:
- initializeDrag(context: IInputModeContext): void
- Initializes the position handler at the start of a drag operation. Implementers should allocate required resources, remember the initial position, and, if applicable, initialize snapping and orthogonal edge editing.
- handleMove(context: IInputModeContext, originalLocation: Point, newLocation: Point): void
- Called during a move gesture to update the current position.
- cancelDrag(context: IInputModeContext, originalLocation: Point): void
- Called when a move gesture is finished. Implementers should restore the initial position and free all resources here.
- dragFinished(context: IInputModeContext, originalLocation: Point, newLocation: Point): void
- Called when a move gesture has finished successfully. Implementers should set the current position and free all resources here.
Customizing Grouping explains how moving nodes to a different parent node as part of a move gesture can be customized.
Moving Unselected Items
GraphEditorInputMode’s moveInputMode only handles items which are selected. That means that the default behavior for moving items is that an item has to be selected before it can be moved. To move items without the need to select them before GraphEditorInputMode provides another input mode. This mode is available via the moveUnselectedInputMode property. By default, this mode is disabled.
Since the moveUnselectedInputMode has the same starting gesture as the CreateEdgeInputMode, you need to take some precautions to avoid concurrency issues. If you don’t disable CreateEdgeInputMode completely, either
- Set the moveUnselectedInputMode's priority higher (i.e. lower priority value) than the CreateEdgeInputMode’s priority. Using a custom modifier recognizer can disable the moveUnselectedInputMode temporarily and allow the user to create edges. See also the example below.
- Switch between CreateEdgeInputMode and moveUnselectedInputMode by setting their enabled property in turn.
- Use a custom hitTestable to restrict the draggable area of a node.
There might be other options. The following example shows how to configure the moveUnselectedInputMode with a higher priority than CreateEdgeInputMode and allow for disabling it by pressing the Shift ⇧ key while dragging.
Moving Labels
Usually, a label cannot be moved freely. Most labels can only be moved to a discrete set of positions, determined by the label’s ILabelModel and ILabelModelParameter.
Multiple candidate positions for moving a label
image::displaying-the-graph_item-layout_labels_interior.png
GraphEditorInputMode supports moving labels via its child input mode MoveLabelInputMode. The MoveLabelInputMode dispatches the same events as the MoveInputMode. It also provides similar configuration options. Additionally,
- movedLabel
- provides access to the label which is currently handled. Similar to MoveInputMode’s affectedItems.
- shouldMove
- can be overridden to allow or disallow moving the given label.
Depending on the label’s lookup the label positions are determined in a different manner:
- If the lookup returns an IPositionHandler this handler will be used. In that case no candidates will be shown and the label is freely movable.
- If the lookup returns an ILabelModelParameterProvider this instance will be used to get the list of candidates. Visualizations will be rendered and the label can only be moved to these positions.
This behavior can be overridden by holding down the Ctrl key during drag or by setting
useLabelModelParameterFinder to true
:
If the lookup returns an ILabelModelParameterFinder this instance
will be used to calculate the closest candidate allowed by the label model. Depending on the
label model this will allow the label to move freely along the positions allowed by the
label model, e.g. moving along at a defined distance to an edge.