Skip to main content
Version: 4.3

RouterService

Keeps a graph's links routed via libavoid and emits events as links are re-routed. Created by initAvoidRouter() - the class is exported as a type only, so instances cannot be constructed directly.

The service mixes in mvc.Events, so on(), off() and trigger() are available on it.

Properties

changeFlag

get changeFlag(): string;

The opt flag name marking the link.set() and element.set() calls this instance makes. Use it to filter the router's own writes out of your change listeners:

graph.on('change:vertices', (link, vertices, opt) => {
if (opt[avoidRouter.changeFlag]) return; // the router's own write
// ... a change made by your application
});

Set with the changeFlag option; defaults to 'avoidRouter'.

isStarted

get isStarted(): boolean;

Whether the router is currently listening to its graph, i.e. start() has been called and not yet followed by stop(). Must be false before calling routeAll() or routeSubgraph().

Methods

start()

start(): void;

Starts listening to graph changes - cells added and removed, elements moved and resized, link ends reconnected - and keeps the graph routed as it changes.

start() also (re-)syncs every cell the graph already holds, including cells added before it was called or while stopped. Calling it on an already started service is safe: it stops first, then starts again.

That initial sync is a full-graph routing pass: it replaces the routing engine's entire state and re-routes every tracked link as one set. After an earlier routeAll() that recomputes the same routes, but it discards what routeSubgraph() produced - the isolation between groups is lost once the whole graph is routed as one.

stop()

stop(): void;

Stops listening to graph changes. Routes already applied to links are left untouched.

destroy()

destroy(): void;

Stops routing the graph and releases the resources held by the service and its provider, terminating the Worker thread when one is in use. Any link with an open routing cycle - link:routing fired for it, but no route ever applied - has that cycle closed with link:routing:cancelled rather than being left stuck.

The instance must not be used after calling this. When swapping one service for another on the same graph, destroy the old one before creating its replacement - see multiple services on one graph.

routeAll()

routeAll(): Promise<RoutingResult>;

Routes every cell currently in the graph in a single one-shot pass, resetting libavoid's state to match exactly the graph's current cells. Unlike start(), this attaches no graph listener - nothing keeps the graph routed as it changes afterwards.

Resolves with a RoutingResult. Throws if the router is started - call stop() first. Overlapping passes are queued and run one after another.

routeSubgraph()

routeSubgraph(cells: dia.Cell[]): Promise<RoutingResult>;

Routes only the given cells in a single one-shot pass, resetting libavoid's state to contain exactly this subset. Cells outside cells are neither routed nor considered as obstacles, and routes already applied to links outside cells are left untouched.

Useful for routing independent groups - each container's own content, for instance - in isolation from one another and from the rest of the graph. Like routeAll(), this attaches no graph listener and throws while the router is started.

await avoidRouter.routeSubgraph(container.getEmbeddedCells());

Events

EventArgumentsDescription
link:routing(link)A link's route is (re-)computing. Emitted once per routing cycle, even if the link changes repeatedly while the computation is in flight.
link:routed(link, { origin, reason })A link's route has been applied, closing its routing cycle. origin is a RouteOrigin; reason is an UnroutableReason, set only when the fallback route was applied because the link could not be routed at all.
link:routing:cancelled(link)A link with an open routing cycle became unroutable - disconnected, removed, or the service destroyed - before libavoid produced a route for it.
idle()There are no more pending routing cycles for any link in the graph.

Every link:routing is closed by exactly one link:routed or link:routing:cancelled.

avoidRouter.on({
'link:routed': (link, { origin, reason }) => {
if (origin === 'fallback') {
console.log(`${link.id} fell back to rightAngle`, reason);
}
},
'idle': () => console.log('All routes settled.')
});

Types

RouteAttributes

interface RouteAttributes {
source: dia.Link.EndJSON;
target: dia.Link.EndJSON;
vertices: dia.Point[];
}

The route to apply to a link. source and target are the link's ends with a modelCenter anchor offset that keeps the link attached where the route enters and leaves the element; vertices are the route's points in between, excluding the end points themselves.

Passed to a SetRouteAttributesCallback.

RouteOrigin

type RouteOrigin = 'avoid' | 'fallback';

Where a route came from: computed by libavoid, or by the built-in rightAngle fallback.

RoutingResult

interface RoutingResult {
status: 'done' | 'cancelled';
}

Outcome of a one-shot routing pass (routeAll() / routeSubgraph()). 'done' when every route was applied, 'cancelled' when the pass was interrupted by destroy() before completing. A cancelled pass resolves rather than rejecting.

UnroutableReason

type UnroutableReason = 'unconnected' | 'untracked' | 'unsupported';

Why a link could not be routed by libavoid:

ValueMeaning
'unconnected'One or both ends are a loose point rather than being connected to a cell.
'unsupported'One or both ends are connected to another link, which libavoid cannot route to.
'untracked'Both ends are connected to an element, but at least one of those elements is excluded via trackElement.