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 SnapGuidesExtension from vyuh_diagram_extension_snap_guides owns alignment snapping end to end: it adjusts selection moves using its SnapGuidesOptions and paints the reported guides as 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 its options.
Source
dart
import 'package:vyuh_diagram_extension_snap_guides/vyuh_diagram_extension_snap_guides.dart';
import 'package:vyuh_diagram_flutter/vyuh_diagram_flutter.dart';
import '../../diagram_extensions.dart';
import 'package:material_ui/material_ui.dart';
import '../connections/cards.dart';
import '../example_canvas.dart';
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.',
createController: () => DiagramController(
document: connectedCardsDocument(),
configuration: DiagramConfiguration(
extensions: [
...demoModelExtensions,
...demoEditing(),
SnapGuidesExtension(),
],
),
),
actionGroups: {
if (policyControls)
'Guide features': ['Sides and centers', 'Sides only', 'Centers only'],
},
selectedActions: (controller) {
final guides = controller.options<SnapGuidesOptions>();
return {
if (guides.policy.sides && guides.policy.centers)
'Sides and centers'
else if (guides.policy.sides)
'Sides only'
else
'Centers only',
'${guides.policy.maxCandidates} candidates',
guides.enabled ? 'Guides on' : 'Guides off',
};
},
actionToggles: {
if (policyControls)
'Guide candidates': (on: '24 candidates', off: '8 candidates'),
'Snap to shapes': (on: 'Guides on', off: 'Guides off'),
},
actions: {
if (policyControls)
'Sides and centers': (s) => configureGuides(
s,
policy: (p) => p.copyWith(sides: true, centers: true),
),
if (policyControls)
'Sides only': (s) => configureGuides(
s,
policy: (p) => p.copyWith(sides: true, centers: false),
),
if (policyControls)
'Centers only': (s) => configureGuides(
s,
policy: (p) => p.copyWith(sides: false, centers: true),
),
if (policyControls)
'8 candidates': (s) =>
configureGuides(s, policy: (p) => p.copyWith(maxCandidates: 8)),
if (policyControls)
'24 candidates': (s) =>
configureGuides(s, policy: (p) => p.copyWith(maxCandidates: 24)),
'Guides on': (s) => configureGuides(s, enabled: true),
'Guides off': (s) => configureGuides(s, enabled: false),
},
);
/// Snap guides are diagram options: changing them adds no document history.
/// Changing the [policy] turns guides on.
void configureGuides(
DiagramController controller, {
bool? enabled,
DiagramSnapGuidePolicy Function(DiagramSnapGuidePolicy policy)? policy,
}) {
final guides = controller.options<SnapGuidesOptions>();
controller.edits.setOptions(
guides.copyWith(
enabled: enabled ?? (policy != null || guides.enabled),
policy: policy?.call(guides.policy),
),
);
}