Connected cards
Loading interactive example…Open in new tab ↗
Move or resize a card and watch its connection follow the bound ports. Switch between straight, orthogonal, quadratic, and Bezier routes. Select the connector and press Enter to edit its label, or use Select label to target it directly.
Router changes are validated transactions and can be undone. Animate starts a transient path effect; Stop animation stops it without editing the document. Reset creates a new controller with empty undo history and clears its effects.
The fixture uses createShape, add for authored connectors, and named BoundEndpoint ports. Label selection uses setSelection(ConnectorLabelSelection(...)); path motion uses controller.effects.play(const Effect.flow(), on: ...) and stopAll. Route changes use setConnectorRoute, sharing the inspector's validation and undo behavior.
See Connectors, Effects, and Undo/redo.
Source
dart
DiagramDocument connectedCardsDocument() {
final seed = DiagramController(
configuration: DiagramConfiguration(
extensions: [...demoModelExtensions, ...demoEditing()],
),
document: DiagramDocument.empty('connected-cards'),
);
try {
for (final (index, title) in ['A bright idea', 'Make it happen'].indexed) {
seed.edits.createShape(
Shapes.card,
id: 'card-$index',
at: DiagramPoint(index * 480, index * 80),
size: const DiagramSize(280, 180),
select: false,
textStory: TextStory(
id: 'story-$index',
blocks: [
TextParagraph(
id: 'title-$index',
role: TextRole.title,
slotId: 'title',
runs: [TextRun(title)],
),
TextParagraph(
id: 'body-$index',
slotId: 'body',
runs: [
TextRun(
index == 0
? 'Sketch a tiny adventure.'
: 'Build it with a friend.',
),
],
),
],
),
);
}
seed.edits.add(
ConnectorElement(
id: 'journey',
start: const BoundEndpoint(elementId: 'card-0', portId: 'right'),
end: const BoundEndpoint(elementId: 'card-1', portId: 'left'),
route: ConnectorRoutes.orthogonal,
labels: [
ConnectorLabel(
id: 'next-step',
story: TextStory.paragraph(
id: 'label-story',
blockId: 'label-block',
text: 'Try it together',
),
),
],
),
select: false,
);
return seed.document;
} finally {
seed.dispose();
}
}