Skip to content

DrawingSession

DrawingSession owns the host-facing connection to one canonical DiagramStore. Content commands work without a canvas; camera and visual-effect commands use the mounted DrawingCanvas.

Constructors

dart
DrawingSession({
  required DiagramDocument document,
  DrawingConfiguration? configuration,
  ShapeRegistry? shapeRegistry,
  DiagramTextLayoutEngine? textLayout,
  DiagramToolRegistry? tools,
  DiagramShapeCreationPolicy? shapeCreationPolicy,
  DiagramConnectionPolicy? connectionPolicy,
  DiagramTool? activeTool,
})

DrawingSession.fromStore(
  DiagramStore store, {
  DrawingConfiguration? configuration,
})
ArgumentTypeDefault / behavior
documentDiagramDocumentRequired for the primary constructor; initial canonical content.
configurationDrawingConfiguration?DrawingConfiguration() when omitted.
shapeRegistryShapeRegistry?Resolver uses ShapeRegistry.standard() when omitted.
textLayoutDiagramTextLayoutEngine?FlutterDiagramTextLayoutEngine() when omitted.
toolsDiagramToolRegistry?Store uses DiagramToolRegistry.standard() when omitted.
shapeCreationPolicyDiagramShapeCreationPolicy?Optional creation policy forwarded to the store.
connectionPolicyDiagramConnectionPolicy?Optional connection policy forwarded to the store.
activeToolDiagramTool?Explicit value, otherwise supplied tools.defaultTool, otherwise DiagramToolIds.select.
store (fromStore only)DiagramStoreRequired positional argument; adopts the existing state, scene, and history.

fromStore borrows the store. Without explicit configuration it projects the store's settings into a default configuration. With configuration it applies those settings, but retains the owning store's admission hook.

Properties

PropertyTypeMeaning
storeDiagramStoreAdvanced access to the same canonical engine.
stateDiagramEditorStateCurrent document, selection, settings, and active tool.
sceneResolvedSceneCurrent resolved geometry.
textDiagramStoryCommandsStory replacement and checklist commands, shared with the canvas editor and headless store.
configurationDrawingConfigurationCurrent host configuration combined with live store settings and admission hook.
canUndo, canRedoboolWhether the respective history operation is available.
canAlign, canDistribute, canReorder, canRemoveFramesboolAvailability for the current selection.
isDisposedboolWhether dispose() has completed.
isAttachedboolWhether a canvas currently claims this session.
cameraStateDiagramCameraState?Mounted camera state, or null when detached.
pathEffectsDiagramPathEffectRegistryCurrent configuration's effect registry.
pathAnimationsMap<String, DiagramPathAnimation>Active animations keyed by animation ID; empty when detached.

Except for isDisposed and isAttached, these getters require a live session.

Content and configuration methods

SignatureReturnsBehavior
addElement(DiagramElement element, {bool select = true})DiagramPolicyDecisionInsert an authored record without factory defaults; see shapes.
createShape({required String type, required DiagramPoint worldCenter, ...})StringMaterialize registry defaults and return the new shape ID; full arguments.
createText({required DiagramPoint worldCenter, ...})StringCreate standalone text; full arguments.
dispatch(DiagramTransaction transaction)DiagramPolicyDecisionSubmits one atomic edit through the store's admission pipeline.
replaceDocument(DiagramDocument document, {required int expectedRevision})DiagramPolicyDecisionRevision-checked replacement; see persistence.
importJson(String json, {required int expectedRevision})DiagramPolicyDecisionDecodes with DiagramJsonCodec, then performs revision-checked replacement. Decode errors propagate.
undo()DiagramPolicyDecisionRequests undo through the canonical store.
redo()DiagramPolicyDecisionRequests redo through the canonical store.
selectElements(Iterable<String> elementIds)voidReplaces object selection; missing and non-selectable elements are filtered by the admitted scene.
selectAll({String? ownerId})voidSelects every selectable element, or only direct children of the supplied owner. Includes connectors.
clearSelection()voidClears selection. Selection commands are transient, preserve document/scene and create no undo entries; they work before mounting.
canGroup / canUngroupboolChecks selection ownership and registered group availability, or removal capability for selected groups. Host admission runs when executing.
groupSelection()DiagramPolicyDecisionGroups at least two objects with the same owner, using admitted selection bounds. Works without a mounted canvas.
ungroupSelection()DiagramPolicyDecisionRemoves selected group containers while retaining children. Nested removals reparent to the first surviving owner, preserving geometry.
copySelection()DiagramClipboardPayloadCaptures selected objects, owned descendants, and connectors whose two bound targets are included, as an immutable payload. Crossing connectors are excluded unless explicitly selected or owned by a captured container. The host owns clipboard storage.
paste(DiagramClipboardPayload payload, {DiagramPoint offset = const DiagramPoint(24, 24)})DiagramPolicyDecisionAllocates fresh identities and inserts through admission as one undo unit. Selects copied selection identities on success.
duplicateSelection({DiagramPoint offset = const DiagramPoint(24, 24)})DiagramPolicyDecisionCopies and pastes selected objects without changing the host clipboard.
setElementsLocked(Iterable<String> ids, bool locked)DiagramPolicyDecisionLocks or unlocks existing objects in one admitted history operation. Missing IDs deny the complete command. Locked owners protect descendants.
canDeleteSelectionboolChecks deletion capabilities for selected objects and their dependants, or the selected connector label. Host admission runs when executing the edit.
deleteSelection()DiagramPolicyDecisionDeletes selected objects or a selected connector label through the engine. Does not delete text-editing content.
removeElements(Iterable<String> elementIds)DiagramPolicyDecisionRemoves objects, descendants and attached connectors as one undo unit. A missing requested ID or protected descendant denies the entire operation. Works without a mounted canvas.
createConnectedShape(DiagramConnectedShapeCreation creation)DiagramConnectedShapeResultCreates a shape and its incoming connection together.
setActiveTool(DiagramTool tool)voidSelects an active tool through the store.
setConfiguration(DrawingConfiguration value)voidApplies behavior and presentation settings without replacing document history.
align(DiagramAlignment alignment)DiagramPolicyDecisionAligns the selection through store.arrangement.
distribute(DiagramDistribution distribution)DiagramPolicyDecisionDistributes the selection through store.arrangement.
reorder(DiagramLayerOrder order)DiagramPolicyDecisionChanges selection stacking through store.arrangement.
removeFrames()DiagramPolicyDecisionRemoves selected frame containers through store.arrangement.

The facade forwards engine command validation and policy results; it does not create a second mutation path. Use the corresponding can… getter to enable arrangement controls.

PNG export

dart
Future<DiagramPngSnapshot> exportPng(
  DiagramPngOptions options, {
  ImageProvider<Object> Function(DiagramImageSource)? imageProvider,
})

Captures the current publication and exports it asynchronously. options is required; imageProvider optionally supplies Flutter image providers. A mounted canvas is not required. Once started, an export survives later edits or session disposal. See persistence and export for output options.

Listeners

SignatureReturnsContract
addListener(DiagramStateListener listener)voidObserves canonical state. Duplicate registration through the session is ignored.
removeListener(DiagramStateListener listener)voidRemoves a registration made through this session; safe after disposal.
addPresentationListener(VoidCallback listener)voidObserves transient camera and path-animation changes separately from content.
removePresentationListener(VoidCallback listener)voidRemoves a presentation listener; no-op after disposal.

DiagramStateListener is void Function(DiagramEditorState state). For completed structured document changes, use configuration.hooks.onChange or advanced store.addDocumentChangeListener(...).

Mounted presentation methods

These methods come from DrawingSessionPresentation and require a mounted canvas.

SignatureReturnsBehavior
screenToWorld(DiagramPoint screenPoint)DiagramPointConverts canvas-local screen coordinates to world coordinates.
globalToWorld(Offset globalPosition)DiagramPointConverts a Flutter global position through the laid-out canvas.
setImageSource(String elementId, DiagramImageSource? source)voidSets an image shape's source; null removes it.
navigateToPoint(DiagramPoint point, {double? zoom})voidCenters on a world point; omitted zoom preserves zoom, supplied zoom is clamped to camera limits.
navigateToRectangle(DiagramRect bounds, {double padding = 48})voidFits world bounds with viewport padding.
navigateToElement(String elementId, {double padding = 48})boolFits the element; false if missing.
navigateToRegion(String elementId, String regionId, {double padding = 48})boolFits the shape region's world bounds; false if unresolved.
navigateToSelection({double padding = 48})boolFits selection bounds; false when no bounds are available.
stopViewportAnimation()voidCancels the current camera animation.
startPathAnimation(DiagramPathAnimation animation)boolAdds/replaces the animation by ID; false for invalid animation, unregistered kind, or missing connector.
stopPathAnimation(String animationId)boolRemoves the animation; false if the ID is absent.
clearPathAnimations()voidRemoves all active path animations.

Animated navigation

Every method returns Future<bool>. Each has these additional named parameters:

ParameterTypeDefault
durationDurationconst Duration(milliseconds: 450)
curveCurveCurves.easeInOutCubic
MethodRequired positional argumentsOther named parameters
animateToPointDiagramPoint pointdouble? zoom
animateToRectangleDiagramRect boundsdouble padding = 48
animateToElementString elementIddouble padding = 48
animateToRegionString elementId, String regionIddouble padding = 48
animateToSelectionNonedouble padding = 48

The future resolves to true on completion and false for a missing target/selection or cancellation. Starting a new camera animation cancels the previous one. Immediate navigation also cancels the current camera animation. Reduced-motion behavior or a nonpositive duration applies the target immediately and returns true.

Lifetime and errors

ConditionResult
replaceDocument / importJson expected revision differs from the current document revisionDiagramRevisionConflict.
Shape creation is denied by creation, connection, or document-admission policyStateError.
Requested creation size is non-finite or nonpositiveArgumentError.
Connected creation specifies an invalid target port, omits a required port, or reuses a connector IDStateError.
Call a live-session API after disposalStateError. Listener removal and repeated dispose() remain safe.
Mount a second canvas on the same sessionStateError; each simultaneous canvas needs a separate session.
Call a mounted presentation method while detachedStateError.
globalToWorld before the canvas is laid outStateError.
setImageSource targets a missing shape or a shape without an image regionStateError.
Image source is neither an HTTP(S) URL nor an image data URIArgumentError.
Borrowed session supplies a non-null admission hook different from the store's hookArgumentError from construction or setConfiguration.
Call dispose() while the canvas is still mountedStateError; unmount first.

void dispose() removes subscriptions made through the session and disposes its controller and configuration notifier. Borrowed-store listeners belonging to other owners are retained. Unmount/remount before disposal retains document and history; runtime settings and path animations are not document content.

Example

dart
final session = DrawingSession(
  document: DiagramDocument.empty('my-drawing'),
  configuration: DrawingConfiguration(
    grid: DrawingGridConfiguration(visible: true),
  ),
);

void onState(DiagramEditorState state) {
  final document = state.document;
  // Persist with DiagramJsonCodec or update host UI from document.
}
session.addListener(onState);

// Return this widget inside a bounded layout:
final canvas = DrawingCanvas(session: session);

// After the canvas is mounted and laid out:
await session.animateToSelection();

// After removing the canvas from the widget tree:
session.removeListener(onState);
session.dispose();

Advanced operations currently use session.store: connections through store.connections, connector labels through store.connectorLabels, and explicit selection through store.setSelection(...). Serialize session.state.document with DiagramJsonCodec and restore with the matching shape registry. See embedding for Flutter lifecycle integration and capability status for remaining foundations.

Paragraph alignment applies only to ordinary paragraphs. Bulleted lists, numbered lists, and checklists remain left-aligned in their region, including nested items. Markers reserve their measured width plus a half-em gap before the item text.

Clipboard references

copySelection() captures resolved endpoint positions for bound targets outside the copied subgraph. paste() remaps internal parents and targets to fresh identities. External references are retained only when pasting into the same document ID and the referenced element still exists. In another document, or after the original target is deleted, external parents are cleared and external endpoints become free endpoints at their captured visible positions plus the paste offset. Matching element IDs in a different document do not establish a binding.

Document IDs identify document identity; independent documents must use distinct IDs. Direct engine callers of DiagramClipboardPayload.capture(document, ids, scene: scene) must supply the current resolved scene when the selection contains external bound endpoints. Missing or revision-mismatched geometry throws ArgumentError. materialize(nextId: ..., targetDocument: ...) uses the same reference rules; omitting targetDocument creates a detached, portable subgraph. The session supplies both automatically.

Arrangement commands return denial for insufficient selection or protected frame removal, and return the host admission decision for edits. An already-satisfied alignment or distribution succeeds without publishing a document change or adding history. Frame removal unwraps children and requires every selected frame to be deletable.

Disposal and store ownership

session.dispose() closes the store created by that session. Retained store and command references can no longer mutate it or register listeners. Dispose is idempotent; unmount the canvas first. Capture session.store.publication before disposal if you need its immutable document and resolved scene afterwards.

DrawingSession.fromStore(store) borrows the store. Disposing that session removes its subscriptions while leaving the store available to its external owner. A headless owner calls store.dispose() when finished. Store disposal clears subscriptions, host policy callbacks, history and pending gesture/group ownership without emitting another change. Disposal during candidate evaluation or publication notification is rejected before cleanup begins.