Drag and Drop
Out of the box, GraphEditorInputMode’s NodeDropInputMode can handle drop events where an INode instance is dropped. A copy of the node will then be created at the location of the drop. Similarly, ILabels and IPorts are handled by LabelDropInputMode and PortDropInputMode, respectively.
However, you can use the drag and drop mechanism in yFiles for HTML to drag and drop anything into the GraphComponent. As usual, an IInputMode is responsible for handling the appropriate events on the GraphComponent.
General Drag and Drop Support
The DropInputMode class provides an abstraction for drop event handling. Each instance of DropInputMode is specific for a ’format’ string that is passed to the constructor. This string serves as an identifier for the input mode and lets you install several input modes that handle different droppped data. The DropInputMode processes any drag events that occur on the GraphComponent and fires its events accordingly if the drag operation carries data of the expected format.
For example, if you wish to process files that are dropped onto the GraphComponent, you could use the following DropInputMode:
Its subclasses ItemDropInputMode<T> and NodeDropInputMode handle only drag and drop operations that carry IModelItems and INodes, respectively.
If you wish to process drag and drop operations for arbitrary types of objects however, you need to configure a DropInputMode appropriately. For this, you can react to the following drag related events:
Event | Occurs when … |
---|---|
For example, you could implement a DropInputMode that accepts strings, so you can drag and drop a string into the GraphComponent and automatically create a node with the droppped string as label by reacting to the DragDropped event as illustrated in the following example:
You can also control the area on which a drop may occur via the validDropHitTestable property. By default, the area is unrestricted. For example, you could set the property to NEVER, thus effectively preventing to drop anywhere, and then only react to the above mentioned drag events:
Drag and Drop of Graph Items
The ItemDropInputMode<T> adds highlight and preview functionality to DropInputMode and is specific for IModelItem. It also supports snapping of the previewed item. You can disable these features as desired using the properties listed below.
- showPreview
- Whether to show a preview of the dragged item during the drag.
- snappingEnabled
- Whether snapping is enabled. Note that a valid snap context either has to be set as snapContext or it has to be retrieved from the IInputModeContext, which is the case if snapping is enabled on the parent GraphEditorInputMode.
- highlightDropTarget
- Whether to indicate a potential drop target item with a highlight visualization.
After a drop operation the ItemDropInputMode<T> delegates the creation of an item to a callback that can be set using the itemCreator property. The callback gets all information needed to create a copy of the dragged item in the GraphComponent’s graph:
Parameter | Description |
---|---|
context | |
graph | |
draggedItem | |
dropTarget | null . |
dropLocation |
A newly created default ItemDropInputMode<T> without a set itemCreator doesn’t do anything on its own. You have to either set an itemCreator or, in the case of INode or IStripe, use the subclasses NodeDropInputMode or StripeDropInputMode. They have an itemCreator set by default to handle dropping the items that they are specified for.
Preview within the GraphComponent
The GraphComponent can display a preview of the currently dragged item with proper snapping support while dragging within the GraphComponent. There are several protected methods that you can override to customize the drop preview:
- initializePreview
- Is called when the drag enters the GraphComponent. The default implementation initializes a separate graph model that is meant to contain the preview items. It then calls the following two methods:
- populatePreviewGraph
- Subclasses are meant to create items that act as a drop preview in this method. The given IGraph instance is not the IGraph of the GraphComponent, but a separate instance that only contains the preview items. The base implementation does nothing.
- updatePreview
- Called for each drag event that occurs while dragging over the GraphComponent. Again, the given IGraph instance is not the IGraph of the GraphComponent but a separate instance that only contains the preview items. The derived classes should update the drop preview items in this method accordingly, e.g. adjusting the preview item’s layout to the drag location or similar.
- cleanUpPreview
- This method is called once the drag and drop operation is completed or canceled and gives client the chance to free resources etc.
The following example shows how to customize the preview to make the preview item transparent:
Preview outside of the GraphComponent
The library provides direct support for two approaches to display a drop preview while dragging the element outside of the GraphComponent.
Providing a Custom Preview Element
A custom preview element can be provided as last argument of the startDrag method. A similar method is also available for the LabelDropInputMode, PortDropInputMode and StripeDropInputMode.
This approach needs pointer-events="none"
support and thus does not
work in IE9 and IE10.
The given element will automatically be included in the DOM and positioned below the pointer location during the drag operation. It will be removed when the gesture is canceled or the element is actually dropped into the GraphComponent.
We recommend to hide this custom preview element while the dragging location is within the GraphComponent and let the ItemDropInputMode<T> display its preview element instead because only then, item snapping can be considered and properly applied to the dragged item.
To hide the custom preview element, a suitable CSS class may be applied when the drag gesture enters the GraphComponent or removed again when the gesture leaves the GraphComponent. The QueryContinueDragEventArgs of the DragSource return value of startDrag. provides a reference to the current DropTarget which can be used to determine if there is a DropTarget that can handle the visualization of the preview element.
The Simple Drag And Drop demo illustrates this approach.
Using native HTML5 Drag and Drop API
The native HTML5 drag and drop API is also supported and may be used as alternative approach for showing a drag preview that is also visible outside of the GraphComponent.
In contrast to the approach of providing a custom preview element, there is no way of letting the ItemDropInputMode<T> take control while the dragged element is within the GraphComponent due to how the HTML5 drag and drop API is designed. Therefore, there is no previewGraph and no snapping support.
To use this approach, the draggable elements need to have the draggable
attribute
set to true
as well as a dragstart
listener that configures some drop properties
and also sets the transfer data to an item ID that represents the actual dragged graph item.
Also, a customized itemCreator needs to provide
different items to insert into the graph.
The transferred data in the drag event may only be strings, which is why we need to
use a map from the node id to the actual node item which holds the information
about the node’s layout, style, tag etc.
Drag and Drop of INodes
The NodeDropInputMode is a specialized ItemDropInputMode<T> for nodes. It specifies the expected format to be ‘INode’.
To customize the creation process of the item that is being dropped, override the createNode method.
The default implementation of the createNode method is very sophisticated and minimizes the effort that is necessary to customize node dropping behavior. We’d recommend to try to configure the NodeDropInputMode properties and override the auxiliary methods like getNodeLayout first to achieve the desired behavior before resorting to override this method. Even then it is probably wise to let the derived class call the super method to let it perform the actual node creation first and then apply the desired customizations to the created node instead of implementing the whole process yourself.
An example for an application that uses the NodeDropInputMode to drag nodes from a palette and drop them into the GraphComponent is the Drag and Drop
Behavior of NodeDropInputMode
In the default configuration, the NodeDropInputMode manages dropping nodes directly into groups. The created node will then be part of that group. You can customize what groups are valid targets for the drop by setting an appropriate isValidParentPredicate.
Furthermore, you can enable additional grouping/folding features on the NodeDropInputMode. For example, you can instruct it to automatically convert regular nodes to group nodes when dragging and dropping a node on it by enabling the allowNonGroupNodeAsParent property.
Additionally, enabling allowFolderNodeAsParent lets you drop nodes into collapsed group nodes, adding them to the corresponding group nodes as well.
Customizing the Dropped Node
NodeDropInputMode provides hooks to alter the node that was created in the IGraph as a result of the drag and drop operation after the operation is completed.
You can:
- Change the location and size of the dropped node by overriding getNodeLayout(mouseLocation: Point, size: Size): Rect.
- Create the node directly as a group node by setting an appropriate isGroupNodePredicate.
- Make alterations to the created node by overriding createNode as mentioned earlier.
Drag and Drop of ILabels
The LabelDropInputMode is a specialized ItemDropInputMode<T> for labels which specifies the expected data format to be ILabel.
To customize the creation process of the item that is being dropped, override the createLabel method.
The default implementation of the createLabel queries the lookup of the provided ILabelOwner for an IEditLabelHelper.
Customizing the Dropped Label
LabelDropInputMode provides hooks to alter the label that was created in the IGraph as a result of the drag and drop operation after the operation is completed.
You can:
- Change the ILabelModelParameter of the dropped label by overriding getNewLabelModelParameter.
- Change the owner of the newly created label by overriding getDropTarget.
Note that returning
null
will prevent a label from being created at the given location. - Make alterations to the created label by overriding createLabel[] as mentioned earlier.
Drag and Drop of IPorts
The PortDropInputMode is a specialized ItemDropInputMode<T> for ports which specifies the expected data format to be IPort.
To customize the creation process of the item that is being dropped, override the createPort method.
The default implementation of the createPort method also copies the labels from the dragged port to the newly created port.
Customizing the Dropped Port
PortDropInputMode provides hooks to alter the port that was created in the IGraph as a result of the drag and drop operation after the operation is completed.
You can:
- Change the IPortLocationModelParameter of the dropped port by overriding getNewPortLocationModelParameter.
- Change the owner of the newly created port by overriding getDropTarget.
Note that returning
null
will prevent a port from being created at the given location. - Make alterations to the created port by overriding createPort as mentioned earlier.