Snap guides
Loading interactive example…Open in new tab ↗
Drag either card near the other. A guide appears when their sides or centers align, and the card snaps into place. Toggle Snap to shapes to compare free movement. Release to commit; undo restores the previous position.
The optional DiagramSnapGuidesExtension draws passive overlays without intercepting pointer input. Guides disappear when the gesture finishes. Alignment applies to selection moves, not resizing.
See Snap guide policy for feature and proximity controls, or Grids API for configuration.
Source
dart
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:material_ui/material_ui.dart';
import 'package:vyuh_diagram_kit/vyuh_diagram_kit.dart';
import '../connections/cards.dart';
import '../example_canvas.dart';
import 'grids.dart' show configureGuides, guidePolicy;
Widget buildExample({bool policyControls = false}) => ExampleCanvas(
title: policyControls ? 'Snap guide policy' : 'Snap guides',
instructions: 'Drag a card near another card to align their sides or centers. Toggle guides to compare free movement. Change the feature policy and nearby candidate limit to explore alignment.',
createSession: () => DrawingSession(
document: connectedCardsDocument(),
configuration: DrawingConfiguration(
extensions: [const DiagramSnapGuidesExtension()],
),
),
actionGroups: {
if (policyControls)
'Guide features': ['Sides and centers', 'Sides only', 'Centers only'],
},
selectedActions: (session) => {
if (guidePolicy(session).sides && guidePolicy(session).centers)
'Sides and centers'
else if (guidePolicy(session).sides)
'Sides only'
else
'Centers only',
'${guidePolicy(session).maxCandidates} candidates',
if (session.canvasConfiguration.extensions
.whereType<DiagramSnapGuidesExtension>()
.any((extension) => extension.enabled))
'Guides on'
else
'Guides off',
session.canvasConfiguration.grid.pattern.label,
session.canvasConfiguration.grid.visible ? 'Show' : 'Hide',
session.canvasConfiguration.grid.snap ? 'Snap on' : 'Snap off',
"${session.canvasConfiguration.grid.size.toInt()} units",
},
labeledToggles: {'Guide candidates'},
actionToggles: {
if (policyControls)
'Guide candidates': (
on: '24 candidates',
off: '8 candidates',
icon: FluentIcons.grid_20_regular,
activeIcon: FluentIcons.grid_20_filled,
),
'Snap to shapes': (
on: 'Guides on',
off: 'Guides off',
icon: FluentIcons.align_center_horizontal_20_regular,
activeIcon: FluentIcons.align_center_horizontal_20_filled,
),
},
actions: {
if (policyControls)
'Sides and centers': (s) => configureGuides(
s,
true,
policy: guidePolicy(s).copyWith(sides: true, centers: true),
),
if (policyControls)
'Sides only': (s) => configureGuides(
s,
true,
policy: guidePolicy(s).copyWith(sides: true, centers: false),
),
if (policyControls)
'Centers only': (s) => configureGuides(
s,
true,
policy: guidePolicy(s).copyWith(sides: false, centers: true),
),
if (policyControls)
'8 candidates': (s) => configureGuides(
s,
true,
policy: guidePolicy(s).copyWith(maxCandidates: 8),
),
if (policyControls)
'24 candidates': (s) => configureGuides(
s,
true,
policy: guidePolicy(s).copyWith(maxCandidates: 24),
),
'Guides on': (session) => configureGuides(session, true),
'Guides off': (session) => configureGuides(session, false),
},
);