Skip to content
D
Documentation

Collaborate on a diagram

how-to
2 min readUpdated

Connect two mounted diagrams to the same transport and give each peer a unique actor id. Local edits then cross the channel as CRDT operations; the other diagram repaints with the converged document. Presence metadata also identifies the peers whose cursors are visible.

Choose a transport

Use the shipped BroadcastChannelTransport for two tabs in one browser. It needs a shared channel name and a distinct actor for each peer. For an in-page test or a controlled offline test, use MemoryHub and connect one transport per actor. For a server-backed product, use the shipped WebSocket transport and keep room, authentication, and storage in your application.

The framework bindings join and leave the session when the component mounts and unmounts. In plain JavaScript, create the session after render returns with createSyncSession and call join().

Mount two peers

The following examples render the same two-node document twice. Change ROOM only once per pair of peers; change actor for every peer. The containers have height so the diagrams have a drawing area.

html
<div id="left" style="height:400px"></div>
<div id="right" style="height:400px"></div>

<script type="module">
import { render } from '@grafloria/element';
import { BroadcastChannelTransport, createSyncSession } from '@grafloria/engine';

const nodes = [
  { id: 'a', label: 'Ingest', position: { x: 60, y: 60 }, size: { width: 150, height: 66 } },
  { id: 'b', label: 'Publish', position: { x: 320, y: 60 }, size: { width: 150, height: 66 } },
];
const edges = [{ id: 'e1', source: 'a', target: 'b' }];
const ROOM = 'diagram-room';

function peer(targetId, actor, name) {
  const target = document.getElementById(targetId);
  const instance = render({ nodes: structuredClone(nodes), edges: structuredClone(edges) }, target);
  const transport = new BroadcastChannelTransport({ name: ROOM, actor });
  const session = createSyncSession(instance.getModel(), transport, {
    actor,
  });
  session.join();
  return { instance, session, name };
}

const left = peer('left', 'ana', 'Ana');
const right = peer('right', 'ben', 'Ben');

// The two mounted peers now share document edits. Keep these handles while the page is open.
void left;
void right;
</script>

Each pane renders the same two nodes. Drag a node in either pane: the corresponding node moves in the other pane. The presence value gives the remote cursor its peer name; presence is not part of the document operation log.

Open the live two-tab collaboration demo
Two panes show the same diagram while edits and the remote collaborator's presence appear across the pair.

Handle interruptions and conflicts

Use disconnect() and connect() on a MemoryTransport when you need to simulate a dropped link. Reconnecting triggers the session's anti-entropy exchange; edits made while disconnected converge after both peers reconnect. The transport must report status for this catch-up path.

Concurrent edits are merged per property. A move on one peer and a rename on another therefore survive together after synchronization, rather than one whole-node edit replacing the other. Viewports remain local: document edits synchronize, but panning and zooming do not.

Options that matter

optiontypedefaultwhat it does
transportSyncTransport—Carries messages between peers.
actorActorId—Identifies the peer; it must be unique across peers.
presenceobject—Supplies presence information such as a collaborator name.
batchfalse or batch options—Controls whether local operations are sent individually or batched.

Pitfalls

  • Give every peer a different actor id. The total order depends on that identity.
  • Use the same channel or hub for peers that must collaborate.
  • Do not expect a disconnected transport to send: send() is a no-op while disconnected.
  • Collaboration provides convergence, presence, comments, and an operation log; rooms, authentication, and persistence remain application responsibilities.

See the live two-tabs demo, the offline and reconnect demo, and the conflict-resolution demo.

Was this page helpful?