Clipboard
The clipboard functionality is controlled by the GraphClipboard defined on the GraphComponent.clipboard property.
GraphClipboard internally holds a separate IGraph that serves as a container for the items to cut/copy/paste. This internal graph is the actual clipboard. To store an item in the clipboard, GraphClipboard copies the elements from and to the internal graph using instances of GraphCopier. You can access these or set your own implementations for further configuration via read/write properties.
- toClipboardCopier
- The GraphCopier which is used for
cut
andcopy
(copying into the clipboard) - fromClipboardCopier
- The GraphCopier which is used for
paste
(copying from the clipboard) - duplicateCopier
- The GraphCopier which is used for duplicating items
As the name suggests, GraphCopier is an object that copies elements from one graph to another. In the GraphClipboard, one of these graphs is the internal clipboard graph and the other the graph of the GraphComponent, depending on which property the GraphCopier is set. This class has several protected methods that deal with the copying of each type of graph element and that can be customized to your needs. See also Copying Elements of a Graph for more customization options.
The clipboard graph itself can be accessed via the clipboardGraph property.
The same GraphClipboard instance can be shared between different GraphComponent instances. For example, an application which maintains several GraphComponents can share the same GraphClipboard instance between them, allowing the user to copy and paste between them.
When invoked as command or from a method on GraphEditorInputMode the following events will be raised after a clipboard operation has been completed:
Event | Occurs when… |
---|---|
The same events will be dispatched by the GraphClipboard itself:
Event | Occurs when… |
---|---|
Besides the events that are dispatched by GraphClipboard after the entire operation has finished, you can also listen for events that are dispatched by the different GraphCopier instances for each copied item individually:
Event | Occurs when… |
---|---|
Additionally, the cut/copy/paste methods have overloads which take a callback function that is invoked once an element has been cut/copied/pasted.
Defining Items to be Copied and Pasted
In the case of copying an element, you can set properties to generally define the types of graph items that are allowed to be copied:
Property | Default | Description |
---|---|---|
Clipboard Operations with Dependent Items
In a graph, only nodes are truly independent items. All other graph elements depend on other elements: Edges depend on their source and target, labels and ports depend on either a node or an edge. Technically they cannot exist without the item on which they depend on, thus copying should theoretically never occur without the other.
Graph items which depend on other items (that means, they cannot exist without them) are automatically copied if the item they depend on is directly or indirectly selected for copy and their type is included in the dependentCopyItems. That means that a label is copied if its owner is copied, even if the label is not selected. The dependencies are resolved recursively, i.e. for a set of nodes which is copied into the clipboard, all their labels and ports will be copied, too. Also, all edges whose both source and target ports are copied are copied, too, as well as all bends, labels, and ports belonging to those edges.
Copy Dependent Items Independently
yFiles for HTML also supports copying items independently even if they are dependent on another item, if the copying logic provides a suitable new target for them. This means that you can for example copy one label from one node to another or edges with only one or no selected source or target node.
Whether these elements can be pasted back to the graph (or another graph) depends on whether an unambiguous appropriate target can be found for these elements. This will be explained in the following in detail:
Copying a node with a single edge
Items copied to the clipboard don’t need to be able to stand alone. While edges in yFiles for HTML cannot exist without a source and target node, they can be copied without one of them. In that case, when pasting a node with an incident edge, the pasted edge can connect to a different node. This is a place where the selection is relevant for pasting, as the selected node will be used as the target for the paste operation, i.e. it becomes the node on the other side of the copied edge.
In the example above, the node C is copied along with its incoming edge. Then A is selected and the copied items are pasted. A is then used as the new source node for the copied edge.
When there is no selection, the original source node of the edge is used instead.
Having multiple nodes selected when pasting will paste the node and edge to all of the selected nodes.
Copying a single dependent item (label or edge)
This is a similar case as the one above: Edges and labels can also be copied without any other items. For edges this means that on pasting two nodes need to be selected to paste the edge between those two nodes. Any other number of selected nodes will cause the edge to be pasted between their original source and target nodes.
When an edge is pasted between two other nodes, their spatial relationship and the spatial relationship between the original source and target nodes will determine which node will become the source and which the target of the pasted edge.
When copying a label without their owning items, it can be pasted to any other potential label owner, even those of different types.
These operations, pasting independent items from the clipboard into a graph,
require finding an appropriate owner (or target).
To change the default behavior described above you can override the getTargetLabeledItem
methods. These methods are queried to return an appropriate owner for the given item (or null
):
- getTargetLabeledItem(clipboardLabel: ILabel): ILabelOwner
- Queried to find an owner for the provided label.
- getTargetPortOwner(clipboardPort: IPort): IPortOwner
- Queried to find an owner for the provided port.
- getTargetPort(clipboardEdge: IEdge, atSource: boolean): IPort
- Queried to find a source or target port for the provided edge.
- getTargetEdge(clipboardBend: IBend): IEdge
- Queried to find an owner for the provided bend.
- getTargetNode(clipboardNode: INode): INode
- Queried to find a parent group node for the provided node.
The items these methods will receive as parameter reside in the clipboard graph while the returned item (the target) must exist in the target graph.
Filtering the Items to be Cut / Copied / Pasted
The cut/copy/paste methods of the GraphClipboard also have overloads which take a predicate function to filter the items which are allowed to be cut/copied/pasted.
For setting general filters, you can override the factory methods for default filters on GraphClipboard. The filters created by these methods are used when cut, copy, paste, or duplicate is invoked from the commands or from GraphEditorInputMode.
Factory Method | Description |
---|---|
The factory methods create filters which use the selection and include dependent and independent items according to the settings.
Using custom filters you can decide for each individual item whether it may be processed or not.
Customizations for Paste
Location of Pasted Items
By default, items are pasted at the location of the items that have been copied.
To avoid that pasted items are placed at the exact location of their original, GraphClipboard places pasted items translated by a pasteDelta that can be adjusted. This offset is increased with each subsequent paste operation when using the PASTE command or GraphEditorInputMode’s paste method so that the newly pasted items don’t overlap the previously pasted items. The pasteDelta is automatically reset upon copy or cut.
You can also specify a concrete location for the paste operation by using GraphEditorInputMode’s pasteAtLocation method or the PASTE command with a Point as parameter. The location is at the center of the bounds of all items that are pasted.
Pasting Items into Group Nodes
yFiles for HTML can be instructed to automatically paste items into a group.
You can specify whether nodes are pasted into a group node and how this node is determined by setting the parentNodeDetection property using the values specified in ParentNodeDetectionModes:
- ROOT
- Always places the nodes in the root (so pasted nodes are never grouped).
- SELECTION
- Places the nodes into the selected node (if there is only one). If combined with ALLOW_SELF a node may be pasted into the original node of itself.
- PREVIOUS_PARENT
- Places the nodes into their original parent if the parent is close enough from the paste location. If combined with FORCE the nodes are always placed into the original parent.
- AT_LOCATION
- Places the nodes into the topmost group node found at the location they will be pasted to. If combined with ALLOW_SELF a node may be pasted into the original node of itself.
These values can be combined with the following modifier values:
- ALLOW_SELF
- Allows to paste a node into the original node of itself. May be combined with SELECTION and AT_LOCATION.
- FORCE
- Forces a node to be pasted into its original parent, even if it is pasted at a location far away from that node. May be combined with PREVIOUS_PARENT
Finding a parent for a pasted node can be customized even further by overriding GraphClipboard’s method getTargetNode(clipboardNode: INode): INode.
Customizing the Clipboard for Individual Items: IClipboardHelper
You can use the IClipboardHelper interface to customize the clipboard behavior for individual graph items. During cut, copy, paste, or duplicate operations GraphClipboard queries each graph item’s lookup for implementations of this interface. The IClipboardHelper provides two groups of methods:
- methods which determine whether the current item should be cut, copied, or pasted
- methods which manage arbitrary additional "state".
The "state" is an arbitrary object. If a custom IClipboardHelper's methods
cut and
copy
return such an object for a copied item, this object is stored internally. When the item is pasted back the helper’s
paste
method gets exactly that object. It is completely up to the IClipboardHelper implementation whether a
state is handled and how the state is handled. If no state is needed, null
can be returned.
- shouldCut(context: IGraphClipboardContext, item: IModelItem): boolean
- Whether the given item should be cut. The item belongs to the original graph. If folding is enabled this item is a view item.
- shouldCopy(context: IGraphClipboardContext, item: IModelItem): boolean
- Whether the given item should be copied. The item belongs to the original graph. If folding is enabled this item is a view item.
- shouldPaste(context: IGraphClipboardContext, item: IModelItem, userData: Object): boolean
- Whether the given item should be pasted. The item belongs to the clipboard graph.
The
userData
object is the state object which is created in one of the next methods. - cut(context: IGraphClipboardContext, item: IModelItem): Object
- Creates an object which can be used to store additional state for the given item.
- copy(context: IGraphClipboardContext, item: IModelItem): Object
- Creates an object which can be used to store additional state for the given item.
- paste(context: IGraphClipboardContext, item: IModelItem, userData: Object): void
- Uses the given state object which has been created by one of the two above methods to restore additional state.
The following example shows an implementation of IClipboardHelper that only permits the copying and cutting of nodes that have a certain tag:
/**
* @param {!IGraphClipboardContext} context
* @param {!IModelItem} item
* @returns {boolean}
*/
shouldCopy(context, item) {
// Don't copy nodes with a red tag
return item.tag !== Color.RED
}
/**
* @param {!IGraphClipboardContext} context
* @param {!IModelItem} item
* @returns {boolean}
*/
shouldCut(context, item) {
// Don't cut nodes with a red tag
return item.tag !== Color.RED
}
/**
* @param {!IGraphClipboardContext} context
* @param {!IModelItem} item
* @param {*} userData
* @returns {boolean}
*/
shouldPaste(context, item, userData) {
return true
}
shouldCopy(context: IGraphClipboardContext, item: IModelItem): boolean {
// Don't copy nodes with a red tag
return item.tag !== Color.RED
}
shouldCut(context: IGraphClipboardContext, item: IModelItem): boolean {
// Don't cut nodes with a red tag
return item.tag !== Color.RED
}
shouldPaste(context: IGraphClipboardContext, item: IModelItem, userData: any): boolean {
return true
}
To use a custom IClipboardHelper, you need to decorate the lookup of the nodes in the graph accordingly:
graph.decorator.nodeDecorator.clipboardHelperDecorator.setImplementation(new PreventCopyingRedNodesClipboardHelper())
Tutorial Demo Code
The tutorial sample application Clipboard demo shows a custom IClipboardHelper implementation. It also demonstrates how the same GraphClipboard instance can be shared between two GraphComponents.