HTMLGraph

Connectable Ports

In some use cases, providing users with interactive graph modification functionality is essential. Part of this functionality is the ability to add new connections to the graph.

To enable ports that are connectable via dragging, call the enableUserConnectablePorts method on a CanvasBuilder instance:

    
const element = document.getElementById("canvas");

const canvas = new CanvasBuilder(element)
  .enableUserConnectablePorts()
  .build();

  

It is crucial for a port to have a “grabable” area large enough to actually be grabbed by the user, as shown in the example below.

The enableUserConnectablePorts method accepts optional configuration.

Configuration Parameters

NameTypeDescriptionRequiredDefault
connectionTypeResolver(portId) => "direct" | "reverse" | nullResolves connection type when edge creation has been initiated. null means that connection is disallowedno() => "direct"
connectionAllowedVerifier(request: { from: Identifier, to: Identifier }) => booleanVerifies if connection between specified ports is allowed.no(request) => true
dragPortDirectionDragPortDirectionDirection of dragging portno"inherit"
connectionPreprocessor(request: AddEdgeRequest) => AddEdgeRequestApplies modifications to the edge about to be created.no(request) => request
grabbedPortIdResolver(portIds: Identifier[]) => Identifier | nullResolves ID of a port being grabbed when there’s ambiguity. See PortIdResolvernoFirst added port
releasedPortIdResolver(portIds: Identifier[]) => Identifier | nullResolves ID of a port being released when there’s ambiguity. See PortIdResolvernoFirst added port
mouseDownEventVerifier(event) => booleanFunction to verify if mouse event should initiate connection creation processno(event) => event.button === 0
mouseUpEventVerifier(event) => booleanFunction to verify if mouse event should create connectionno(event) => event.button === 0
edgeShapeEdgeShapeConfigDefault edge shape configuration while port is in the process of draggingnoSame as for canvas
eventsEventsConfigHandlers for available eventsno{}

Here’s a good example of a reasonable connection type resolver, which resolves direct connection when an “out” port gets grabbed, and reverses connection when an “in” port gets grabbed:

    
const connectionTypeResolver = (portId) => {
  return portId.endsWith("-out") ? "direct" : "reverse";
};

  

As for the connection allowed verifier, you can start with one that forbids duplicated connections:

    
const connectionAllowedVerifier = (request) => {
  const existingEdge = canvas.graph.getAllEdgeIds().find((edgeId) => {
    const edge = canvas.graph.getEdge(edgeId);

    return edge.from === request.from && edge.to === request.to;
  });

  return existingEdge === undefined;
};

  

DragPortDirection

NameTypeDescription
ConstantnumberFixed radian angle for the dragging port direction
Nearest Connectable Port"nearest-connectable-port"Direction matches the direction of the nearest connectable port
Inherit"inherit"Direction matches the original direction of the port being grabbed

PortIdResolver

The same element can be marked as multiple different ports. When user interacts with such element, it’s not clear which port should be interacted with, for example when grabbed or released.

PortIdResolver function allows to configure such behavior.

There are good examples of such functions:

    
const grabbedPortIdResolver = (portIds) => {
  return portIds.find((portId) => portId.endsWith("-out")) ?? null;
}

const releasedPortIdResolver = (portIds) => {
  return portIds.find((portId) => portId.endsWith("-in")) ?? null;
}

  

EventsConfig

NameTypeDescriptionRequiredDefault
onAfterEdgeCreated(edgeId) => voidFunction called after a new edge has been addedno() => void
onEdgeCreationInterrupted(params: { staticPortId, isDirect: boolean}) => voidFunction called when edge creation is interrupted in the processno() => void
onEdgeCreationPrevented(request: AddEdgeRequest) => voidFunction called when an attempt to create edge is preventedno() => void

You might also be interested in the Edges with Remove Button tutorial.