Skip to main content
Version: 4.3

Standalone Link Routing

@joint/router-avoid routes every link in the graph around the elements in the way, and re-routes as they move. It is a service attached to the graph, not a router you set on a link - see the core guide for how it works and what it can do. This page is the React setup.

Installation

npm add @joint/router-avoid

Setup

initAvoidRouter(graph) needs the graph, so wrap it in a hook and call it from a component inside <GraphProvider>:

import { useEffect } from 'react';
import { useGraph } from '@joint/react';
import { initAvoidRouter, type RouterService } from '@joint/router-avoid';

function useAvoidRouter() {
const { graph } = useGraph();

useEffect(() => {
let router: RouterService | null = null;
let cancelled = false;

async function setup() {
const created = await initAvoidRouter(graph, { shapeBufferDistance: 20 });
if (cancelled) {
created.destroy();
return;
}
router = created;
router.start();
}

setup();

return () => {
cancelled = true;
router?.destroy();
};
}, [graph]);
}
  • start() attaches the router to the graph. Without it nothing is routed.
  • initAvoidRouter is async (it loads a WebAssembly module). The cancelled flag handles an unmount before it resolves; destroy() in the cleanup handles one after.
  • The router writes routes straight onto the links. Nothing to wire on <Paper>.

Without a hook

If the graph is created outside React anyway, set up the router next to it and pass the graph in:

import { dia, shapes } from '@joint/core';
import { ElementModel, LinkModel, GraphProvider } from '@joint/react';
import { initAvoidRouter } from '@joint/router-avoid';

const graph = new dia.Graph({}, {
cellNamespace: { ...shapes, element: ElementModel, link: LinkModel },
});
graph.resetCells(initialCells);

const router = await initAvoidRouter(graph, { shapeBufferDistance: 20 });
router.start();

<GraphProvider graph={graph}></GraphProvider>

The namespace entries let type: 'element' / type: 'link' records resolve on a graph you created yourself.

Ports

Links connected to portMap ports are routed to the port, approaching from the side it sits on. Nothing to configure - source: { id, port } is enough. Drag an element below to see the routes recompute:

The demo points libavoidFilePath at a CDN because the sandbox can't serve the .wasm itself - in your app, serve it from your own bundle.

Large graphs and performance

By default routing runs on the main thread. On a few hundred cells a routing pass takes long enough to block the UI - dragging stutters while the routes are computed. Pass worker to run it in a Web Worker instead and keep the UI responsive. Nothing else changes; destroy() terminates the Worker too.

initAvoidRouter(graph, { worker: { debounceTime: 250 } });

debounceTime is how long the Worker waits after the last change before routing the whole batch at once - raise it when many cells move together.

Your bundler has to emit the package's Worker module - Vite and webpack 5 do, with one Vite dev-server snag; see Running in a Worker. No live demo here, the sandbox can't bundle it.

For a complete React setup - a flowchart of up to 2000 cells routed off the main thread, with a readout of how long each pass took - see the Standalone Link Routing demo in joint-demos.

Going further

Options, events, one-shot routing, fallback routes: core guide and API reference.

Stay in the know

Be where thousands of diagramming enthusiasts meet

Star us on GitHub