documentationfor yFiles for HTML 2.6

Reconnecting Edges

Edge reconnection means moving an edge’s source or target to another port. In yFiles for HTML this is done by selecting an edge and dragging the handle which represents its source or target port. Edge reconnection is enabled by default, but the edges can only be reconnected to ports at the same owner when not Providing Port Candidates for other nodes.

The following steps are involved when reconnecting edges:

  • When selecting an edge and a HandleInputMode is active, IHandles are calculated for the source and target port of the edge:
  • HandleInputMode visualizes these handles and delegates drag gestures to the PortRelocationHandles.
  • When initializing a drag, PortRelocationHandle calculates possible port candidates the edge may reconnect to:

All those steps can be adjusted for a customized reconnection behavior. The most common adjustments include Providing Port Candidates and Customizing the Reconnection Gesture.

Providing Port Candidates

Possible candidates for new source and target nodes are provided by implementations of IEdgeReconnectionPortCandidateProvider which are queried from the edge’s lookup. During reconnections the following methods are queried to return a list of port candidates:

Method Description
getSourcePortCandidates(IInputModeContext)Queried for a list of all possible candidates for an edge’s source port.
getTargetPortCandidates(IInputModeContext)Queried for a list of all possible candidates for target ports.

Implementers have to implement above methods to return an appropriate list of candidates. Note that this list may be empty (or contain only invalid candidates) if an edge cannot be reconnected. The concept of port candidates is explained above.

yFiles for HTML already provides a number of IEdgeReconnectionPortCandidateProvider implementations for the most common use cases which are available through factory methods or constants on the IEdgeReconnectionPortCandidateProvider interface:

Predefined edge reconnection port candidate providers
Constant / Factory Method Description
ALL_NODE_CANDIDATESAn IEdgeReconnectionPortCandidateProvider that queries all nodes for their IPortCandidateProvider implementation and returns a union of all port candidates returned by their getAllSourcePortCandidates or getAllTargetPortCandidates methods.
ALL_NODE_AND_EDGE_CANDIDATESAn IEdgeReconnectionPortCandidateProvider that queries all nodes and edges for their IPortCandidateProvider implementation and returns a union of all port candidates returned by their getAllSourcePortCandidates or getAllTargetPortCandidates methods.
fromSourceAndTargetCreates an IEdgeReconnectionPortCandidateProvider which queries the edge’s source and target port owner, respectively, for an IPortCandidateProvider which then is queried to return a list of port candidates. This allows to reconnect edges only to other ports on the same node. This is the default implementation.

The edge’s lookup has to be modified to return an instance of the new provider. You can do this using an EdgeDecorator:

graph.decorator.edgeDecorator.edgeReconnectionPortCandidateProviderDecorator.setImplementation(
  IEdgeReconnectionPortCandidateProvider.ALL_NODE_CANDIDATES
)

For folding-enabled graphs it is mandatory to decorate the master graph. Decorating the view graph may result in an exception during the edge reconnection.

The tutorial demo application Edge Reconnection shows how to implement IEdgeReconnectionPortCandidateProvider for different purposes.

Customizing the Reconnection Gesture

The actual dragging is mediated by IHandle implementations and by default a PortRelocationHandle is used. It provides a number of settings which control behavior and appearance of the handle. The most common are listed below:

Property Description true false
showPortCandidatesWhether to show port candidates. Default is true.
showHitPortOwnerCandidatesOnlyWhether to show the candidates of hit IPortOwners only. Default is true.
showTargetHighlightWhether the owner of the current port candidate should be highlighted. Default is true.

Additionally, the maximum distance the pointer may be away of a candidate in order to be snapped to the candidate can be set via maximumSnapDistance.

The appearance of the edge during the movement gesture can be determined with visualization. The effect is visualized below, default is DUMMY:

Visualization modes during edge reconnection
NONEGHOSTDUMMYLIVE
Visualization.NONEVisualization.GHOSTVisualization.DUMMYVisualization.LIVE
Only the handle is visualized during movement, the original edge is not changed.A symbolized view of the edge visualized during movement, the original edge is not changed.A copy of the edge (a dummy edge) is shown during movement, the original edge is hidden. Note that decorations like labels are not moved with the dummy edge.The original edge, together with all its decorations, is moved.

The PortRelocationHandle cannot be decorated directly to edges. Instead instances of this IHandle are provided by the PortRelocationHandleProvider. It can be decorated using the edgeDecorator's edgePortHandleProviderDecorator. The most commonly used settings are available on the PortRelocationHandleProvider, too:

graph.decorator.edgeDecorator.edgePortHandleProviderDecorator.setFactory((edge) => {
  const portRelocationHandleProvider = new PortRelocationHandleProvider(graph, edge)
  portRelocationHandleProvider.visualization = Visualization.LIVE
  portRelocationHandleProvider.showPortCandidates = false
  return portRelocationHandleProvider
})

For less frequently used settings a custom PortRelocationHandleProvider has to be provided and its createPortRelocationHandle method has to be overridden to provide the configured PortRelocationHandle:

graph.decorator.edgeDecorator.edgePortHandleProviderDecorator.setFactory((edge) => {
  const portRelocationHandleProvider = new MyHandleProvider(graph, edge)
  portRelocationHandleProvider.visualization = Visualization.LIVE
  portRelocationHandleProvider.showPortCandidates = false
  return portRelocationHandleProvider
})

class MyHandleProvider extends PortRelocationHandleProvider {
  /**
   * @param {!IGraph} graph
   * @param {!IEdge} edge
   * @param {boolean} sourceEnd
   * @returns {!PortRelocationHandle}
   */
  createPortRelocationHandle(graph, edge, sourceEnd) {
    const portRelocationHandle = new PortRelocationHandle(graph, edge, sourceEnd)
    portRelocationHandle.addExistingPort = true
    return portRelocationHandle
  }
}
graph.decorator.edgeDecorator.edgePortHandleProviderDecorator.setFactory((edge) => {
  const portRelocationHandleProvider = new MyHandleProvider(graph, edge)
  portRelocationHandleProvider.visualization = Visualization.LIVE
  portRelocationHandleProvider.showPortCandidates = false
  return portRelocationHandleProvider
})

class MyHandleProvider extends PortRelocationHandleProvider {
  createPortRelocationHandle(graph: IGraph, edge: IEdge, sourceEnd: boolean): PortRelocationHandle {
    const portRelocationHandle = new PortRelocationHandle(graph, edge, sourceEnd)
    portRelocationHandle.addExistingPort = true
    return portRelocationHandle
  }
}