Skip to content

Departmental swimlanes

Each department is an ordinary frame. Tasks belong to that frame through their saved parentId; connections keep their task bindings when lanes move.

Swimlanes use the same parenting, unparenting, movement and optional collapse as frames. Clipping is a separate choice: enable clipsChildren on the definition and clipContent on a lane to hide overflow while expanded. This example leaves clipping disabled. arrangeLanes arranges the frames, not the tasks inside them.

Loading interactive example…Open in new tab ↗
Opening the live canvas…

For domain review, choose Task ownership → Detach review task, then Run checks. Select the finding to locate the task and Quality department. Assign review to Quality repairs the ownership; run checks again to clear the finding. Undo restores the draft. This host-defined rule reports incomplete work without blocking edits or adding domain policy to the engine.

  • Arrange columns places departments side by side. Their frames change size; task sizes stay unchanged.
  • Arrange rows restores horizontal lanes in Production, Quality, Release order. Both arrangements leave a 32-unit gap between departments.
  • Collapse Quality shows the department summary and redirects external links. Expand Quality restores its task before arranging the lanes again.
  • Undo restores an entire lane arrangement in one step.
  • Command-drag a task to transfer it between departments, or outside all departments to release it. Use Control on other platforms. Its bounds only need to intersect the destination; the destination outline is highlighted. Ordinary dragging keeps its current parent. Escape cancels movement and ownership changes.
dart
session.arrangeLanes(
  ['production', 'quality', 'release'],
  direction: DiagramLaneDirection.rows,
  laneSize: const DiagramSize(720, 180),
  gap: 32,
);

The ID order determines lane order. Omit laneSize to preserve existing sizes; gap defaults to zero. The arrangement starts at the current lanes' upper-left corner. Lanes must be expanded, unrotated sibling frames. Moving a locked or fixed child rejects the whole operation. Resizing a lane does not automatically fit its contents: hosts choose the lane size and clipping behavior explicitly.

Transfer ownership with session.reparentElements(['task'], parentId: 'quality'). This preserves world positions; it changes membership without silently laying out the task. Pass no parent to return objects to the root. Transfers, lane movement, deletion, save/load and undo use the ordinary document commands.

To move and transfer together, pass a world-coordinate delta. The engine carries descendants without resizing them and records the entire operation as one undo:

dart
session.reparentElements(
  ['task'],
  parentId: 'quality',
  delta: const DiagramPoint(32, 48),
).requireAllowed();

A locked descendant rejects the movement without partially changing ownership or positions. Omit delta to change membership while preserving world positions.

On macOS, Command+G groups a selection, Command+Option+G frames it, and Command+Shift+G removes selected groups or frames while keeping their contents. Use Control instead of Command on other platforms. Removing a collapsed frame releases its children as well; Undo restores the container and membership.

Source

dart
actions: {
  'Arrange rows': (s) => s
      .arrangeLanes(laneIds, laneSize: const DiagramSize(720, 180), gap: 32)
      .requireAllowed(),
  'Arrange columns': (s) => s
      .arrangeLanes(
        laneIds,
        direction: DiagramLaneDirection.columns,
        laneSize: const DiagramSize(240, 540),
        gap: 32,
      )
      .requireAllowed(),
  'Collapse Quality': (s) =>
      s.setFrameCollapsed('quality', true).requireAllowed(),
  'Expand Quality': (s) =>
      s.setFrameCollapsed('quality', false).requireAllowed(),
},