Embed a canvas
Keep one DrawingSession for the lifetime of a mounted canvas. It owns the document, registries, configuration, commands, and lifecycle. It also exposes camera navigation and mounted presentation operations. Recreating it during every build resets document and interaction ownership.
See the drawing API for the complete object model and command surface, including connections, mutations and current limitations.
Minimal surface
This widget supplies an empty document, the standard shape registry, and optional minimap navigation. Toolbars and other extensions are explicit session configuration choices.
dart
import 'package:flutter/widgets.dart';
import 'package:vyuh_diagram_kit/vyuh_diagram_kit.dart';
class DiagramSurface extends StatefulWidget {
const DiagramSurface({super.key});
@override
State<DiagramSurface> createState() => _DiagramSurfaceState();
}
class _DiagramSurfaceState extends State<DiagramSurface> {
late final session = DrawingSession(
document: DiagramDocument.empty('my-document'),
shapeRegistry: ShapeRegistry.standard(),
configuration: DrawingConfiguration(
extensions: [const DiagramMinimapExtension()],
),
);
@override
void dispose() {
session.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => SizedBox.expand(
child: DrawingCanvas(session: session),
);
}Mount this inside a bounded Flutter layout. A resizable desktop pane or an Expanded child in an application shell can provide those constraints.
Dispatch intent
Create shapes through the session, before or after mounting a view. Registry defaults supply appearance and size:
dart
String addCard(DrawingSession session) {
return session.createShape(
type: BuiltInShapeType.card,
worldCenter: const DiagramPoint(300, 200),
);
}session.undo() and session.redo() use the same history as interactive edits. Domain integrations may dispatch canonical transactions through session.dispatch(...); they should not retain a second editable copy of the diagram.
Update the experience
Keep view choices on the same session. A configuration update changes the mounted presentation without replacing the document or resetting history:
dart
session.setConfiguration(
session.configuration.copyWith(
canvasPolicy: const InfiniteCanvasPolicy(),
extensions: [const DiagramMinimapExtension()],
),
);
session.setConfiguration(session.configuration.copyWith(
grid: session.configuration.grid.copyWith(visible: true),
));
session.setActiveTool(DiagramToolIds.draw);DrawingCanvas(session: session) is the view. Mount a session in one view at a time. Shape creation, transactions, settings, and history work without a mounted view; camera animation requires attachment. Use session.canUndo and session.canRedo to enable host history controls.
Save and restore
dart
String saveDocument(DrawingSession session) =>
const DiagramJsonCodec().encode(session.state.document);
DrawingSession restoreDocument(String json, ShapeRegistry registry) =>
DrawingSession(
document: const DiagramJsonCodec().decode(json),
shapeRegistry: registry,
);Restore with definitions for every shape type used by the document. Registry admission remains part of loading into a session. Save document content separately from runtime presentation such as active path effects; those effects are not currently persisted by the diagram codec.
Animate navigation
dart
Future<bool> focusCard(DrawingSession session, String elementId) =>
session.animateToElement(
elementId,
padding: 64,
duration: const Duration(milliseconds: 350),
);The session also exposes animateToPoint, animateToRectangle, animateToRegion, animateToSelection, and stopViewportAnimation. Camera changes do not rewrite shape coordinates or create document history entries.
Use configuration.hooks.beforeChange for shared document admission and hooks.onChange for completed edits. Region and connection callbacks also live in hooks; imageSourcePicker stays in the session configuration. Subscribe through session.addListener and remove subscriptions with session.removeListener; dispose the owning session when its view is removed.