Skip to content

Canvas, camera, and grids ​

Configure the camera, grid and minimap without changing document content.

Import the Flutter package, plus the editor and minimap extension packages when you install them:

dart
import 'package:vyuh_diagram_flutter/vyuh_diagram_flutter.dart';
import 'package:vyuh_diagram_extension_editor/vyuh_diagram_extension_editor.dart';
import 'package:vyuh_diagram_extension_minimap/vyuh_diagram_extension_minimap.dart';

Everything a canvas does is configured on its controller. The canvas takes the controller and an optional theme, and uses the extensions installed on that controller:

dart
final controller = DiagramController(
  document: document,
  configuration: DiagramConfiguration(
    extensions: [
      EditorExtension(),
      GridExtension(visible: true, snap: true),
      MinimapExtension(),
    ],
  ),
);

DiagramCanvas(controller: controller, theme: DiagramTheme.light);

Install EditorExtension() to edit. Without an editor the canvas is view-only: people pan, zoom and select, but cannot edit on the canvas. For an editable canvas without the palette, inspector and toolbar, install EditorExtension(palette: false, inspector: InspectorPlacement.none, toolbar: false).

Each extension owns its options. Read the current value with controller.options<T>() and change it with controller.edits.setOptions(value); observers of options<T>() rebuild when it changes. Options changes apply to every controller of the diagram and are not undoable.

Move the viewpoint ​

Pan and zoom without rewriting shape coordinates. Fit the document or selection, or travel to an element after the canvas has mounted:

dart
await controller.view.show(
  ViewTarget.element(elementId),
  motion: const Motion(duration: Duration(milliseconds: 500)),
);

controller.view.show also targets points, rectangles, regions, the selection and the whole diagram, with or without motion. User navigation interrupts a move.

A canvas is infinite by default. The bounds are core configuration: pass DiagramConfiguration(bounds: CanvasBounds.fit(padding: 48)) to start bounded, or change them later:

dart
controller.edits.setBounds(const CanvasBounds.fit(padding: 48));

controller.bounds is observable. A fit canvas is the diagram's content extent plus padding viewport pixels, growing and shrinking with the content, and it keeps the camera within it. An empty document gets a viewport-sized canvas around the origin.

Choose a grid ​

The grid is always installed. Its GridOptions hold visible, snap, size and pattern. Visibility and snapping are independent: showing a grid does not turn snapping on, and snapping can stay enabled while the grid is hidden. Set the initial values by installing GridExtension(...), which replaces the default grid:

dart
final controller = DiagramController(
  configuration: DiagramConfiguration(
    extensions: [
      GridExtension(
        visible: true,
        snap: true,
        pattern: DiagramGridPattern.dots,
      ),
    ],
  ),
);

final grid = controller.options<GridOptions>();
controller.edits.setOptions(grid.copyWith(size: 40));

Choose dots, lines, or layered. Layered grids combine fine and major lines. Every pattern uses the same grid spacing as snapping. At distant zoom levels, the painter thins visible grid marks while preserving the snapping interval.

Compose your own pattern ​

Custom patterns use the same dot, line, and cross productions as the defaults. Colors, screen-space mark sizes, and spacing multiples belong to each layer:

dart
final engineeringGrid = DiagramGridPattern(
  id: 'engineering',
  label: 'Engineering',
  layers: [
    DiagramDotGridLayer(color: DiagramColor(0xFFBBC9E8), size: 2),
    DiagramLineGridLayer(spacingMultiple: 5, color: DiagramColor(0xFF8296C7)),
  ],
);

controller.edits.setOptions(
  controller.options<GridOptions>().copyWith(pattern: engineeringGrid),
);

To offer it in the property panel's grid type list, pass it to GridExtension(patterns: [...DiagramGridPattern.presets, engineeringGrid]); the list is GridOptions.patterns, and duplicate pattern ids throw an ArgumentError.

Patterns are validated, immutable compositions. A custom pattern changes the painted grid, not the document geometry or snapping rules. Arbitrary custom renderer callbacks are not part of this grid contract.

Set the minimap detail policy ​

The minimap defaults to shape outlines and fills, without connections. It uses resolved shape geometry and clipping; text, handles and detailed editing chrome are omitted.

dart
final controller = DiagramController(
  configuration: DiagramConfiguration(
    extensions: [
      EditorExtension(),
      MinimapExtension(
        initiallyExpanded: true,
        policy: DiagramMinimapPolicy(
          shapeAppearance: DiagramMinimapShapeAppearance.outlines,
          showConnections: false,
        ),
      ),
    ],
  ),
);

// Hide or show it at runtime, keeping its other options.
controller.edits.setOptions(
  controller.options<MinimapOptions>().copyWith(visible: false),
);

Use outlinesAndFills for colored silhouettes, or opt into showConnections. A policy can provide shapePainterForType for custom registered types. Thumbnail painters receive resolved geometry and must remain deterministic; replacing the policy refreshes external thumbnail inputs. They affect presentation only.

Camera movement reuses a recorded scene picture. Document or policy changes rebuild that picture, so a changed scene still costs work proportional to its shapes. Thousands of shapes are not automatically a constant-cost or 120 fps minimap; measure the representative document and chosen thumbnail policy.

Particle count and size ​

Count controls the number of particles evenly distributed along a path. It does not shrink their dimensions. Size is the radius for circles and polygons; character particles use a font scale of twice that value. Dash length is eight times size, capped only by total path length, while width sets dash thickness. The configured screen/world scaling policy controls zoom behavior. Dense particles can overlap.