Skip to content

Engine API ​

createVisualLinker(container, config?) — the framework-agnostic engine every other part of the package is built on. You own the block elements and their position; this measures them and draws the SVG connections.

ts
function createVisualLinker(container: HTMLElement, config?: VisualLinkerConfig): VisualLinker

Renders into an absolutely-positioned <svg> layer the engine creates inside container. The engine gives container a positioning context automatically (position: relative, only if its computed position was static) so that overlay lines up with the blocks inside it — no manual CSS needed.

Configuration ​

config is a VisualLinkerConfig: one object, grouped into theme, lines, markers, ports, labels, blocks and interaction. Every field is optional. The groups and their fields are described in Configuration, the colors in Themes, and the hover, selected and focus looks in Visual States.

Example:

ts
const linker = createVisualLinker(diagramEl, {
  theme: darkTheme, // colors of lines, ports and labels, in one place
  lines: {
    curve: 'smoothstep',
    width: 2,
    hover: { width: 3 },
    routing: { avoidObstacles: true },
    jumps: true,
  },
  markers: { end: { shape: 'arrow', hover: { size: 10 } } },
  ports: { radius: 5, spread: true },
  blocks: { draggable: true, drag: { grid: 20, bounds: 'container' } },
  interaction: { selectable: true },
})

Methods ​

setBlocks(blocks: BlockDescriptor[]): void ​

Replaces the full set of blocks the engine measures and draws connections between. See Blocks & Ports for BlockDescriptor's shape. Triggers an immediate render.

setConnections(connections: ConnectionDescriptor[]): void ​

Replaces the full set of connections. See Connections for ConnectionDescriptor's shape. Triggers an immediate render.

updateBlock(id: string, patch: Partial<Omit<BlockDescriptor, 'id'>>): void ​

Merges patch into the block with the given id — e.g. to change its ports or draggable flag without re-passing every other block. No-op if id isn't currently registered.

addConnection(connection: ConnectionDescriptor): void ​

Adds a single connection without replacing the others.

removeConnection(id: string): void ​

Removes a single connection by id.

setSelectedConnections(ids: readonly string[]): void ​

Replaces the set of selected connections — for driving the selection from your own state (needs interaction.selectable). Ids that aren't among the current connections are ignored. Emits no event. See Selection & Accessibility.

setConfig(patch: VisualLinkerConfig): void ​

Deep-merges patch into the current configuration and redraws. A key set to undefined is removed. Listeners follow the change: blocks.draggable and interaction.selectable attach or detach what they need. See Configuration.

replaceConfig(next: VisualLinkerConfig): void ​

Replaces the whole configuration with next and redraws.

getConfig(): VisualLinkerConfig ​

Returns a copy of the configuration in effect. Changing the copy does not change the engine.

refresh(): void ​

Forces an immediate path recalculation, bypassing the engine's requestAnimationFrame batching — useful right before taking a screenshot of the diagram.

on(event, handler): () => void ​

Subscribes to an engine event (see Events below). Returns an unsubscribe function.

destroy(): void ​

Tears down every listener (resize/scroll/pointer), clears all blocks and connections, and removes the SVG layer. Call this when the container is about to leave the DOM — <VisualLinker> and useVisualLinker() both already do this for you on unmount.

Events ​

Subscribe via linker.on(eventName, handler).

block:dragstart ​

{ blockId: string }

Fired when a block drag starts.

block:drag ​

{ blockId: string; x: number; y: number }

Fired on every pointer move during a drag, with the block's current offset from its base position.

block:dragend ​

{ blockId: string; x: number; y: number }

Fired when a block drag ends, with its final offset.

block:mouseenter ​

{ blockId: string }

Fired when the pointer enters a block — with interaction.highlight on (or highlightable on the block), it also puts every connection incident to it into the highlight state.

block:mouseleave ​

{ blockId: string }

Fired when the pointer leaves a block.

connection:click ​

{ connection: ConnectionDescriptor }

Fired when a connection's line (or its wider invisible hit area) is clicked.

connection:mouseenter ​

{ connection: ConnectionDescriptor }

Fired when the pointer enters a connection's line — with interaction.hover on (or hoverable on the connection), it also puts it into the hover state.

connection:mouseleave ​

{ connection: ConnectionDescriptor }

Fired when the pointer leaves a connection's line.

connection:selectionchange ​

{ selectedIds: string[] }

Fired when the set of selected connections changes because of user input (interaction.selectable mode) — not for a setSelectedConnections() call.

connection:delete-request ​

{ connections: ConnectionDescriptor[] }

Fired when Delete or Backspace is pressed on a focused connection: the selected connections, or just the focused one when it isn't selected. Nothing is removed — the app decides.

layout ​

{ connections: ConnectionLayout[]; ports: PortLayout[] }

Fired at the end of every render pass with every connection's and port's resolved geometry (points, angles, midpoints) — this is what drives the Vue component's #connection-label/#port/#marker overlay slots. Useful for positioning your own custom overlay content when using the engine directly. Each ConnectionLayout also carries labels — every label resolved to a point and angle on the line — and fromClipped / toClipped, set when an end was pinned to the edge of a clipping ancestor.