BetaTry our live BPMN Workflow EditorSkip to content

Configuration

Node Flow uses a configuration system with two components: NodeFlowConfig for core behavioral settings and an plugin system for features like minimap, autopan, and debug visualization.

NodeFlowConfig

NodeFlowConfig is a reactive configuration class that controls core behavioral properties of the editor. Most properties are MobX observables, allowing real-time updates.

Constructor

dart
NodeFlowConfig({
  bool snapToGrid = false,
  bool snapAnnotationsToGrid = false,
  double gridSize = 20.0,
  double portSnapDistance = 8.0,
  double minZoom = 0.5,
  double maxZoom = 2.0,
  bool showAttribution = true,
  List<NodeFlowPlugin>? plugins,
})

Properties

PropertyTypeDefaultDescription
snapToGridObservable<bool>falseSnap node positions to grid when dragging
snapAnnotationsToGridObservable<bool>falseSnap annotation positions to grid
gridSizeObservable<double>20.0Grid cell size in pixels for snapping
portSnapDistanceObservable<double>8.0Distance threshold for port snapping during connection
minZoomObservable<double>0.5Minimum zoom level (0.5 = 50%)
maxZoomObservable<double>2.0Maximum zoom level (2.0 = 200%)
showAttributionbooltrueWhether to show the attribution label
pluginsList<NodeFlowPlugin>?default pluginsPlugins for minimap, autopan, debug, etc.
Snap-to-Grid Behavior

Split-screen animation: left side shows free-form node dragging (smooth movement), right side shows snap-to-grid enabled (nodes jump to grid intersections). Visual grid overlay shows the 20px grid cells.

Default Plugins

If no plugins are provided, the following defaults are used:

  • AutoPanPlugin - autopan near viewport edges (enabled by default)
  • DebugPlugin - debug overlays (disabled by default)
  • LodPlugin - level of detail (disabled by default)
  • MinimapPlugin - minimap overlay
  • StatsPlugin - performance statistics display (disabled by default)

Basic Usage

dart
// Create controller with configuration
final controller = NodeFlowController<MyData, dynamic>(
  config: NodeFlowConfig(
    snapToGrid: true,
    gridSize: 20.0,
    plugins: [
      MinimapPlugin(visible: true),
      AutoPanPlugin(),
    ],
  ),
);

// Access config from controller
final gridSize = controller.config.gridSize.value;

Reactive Updates

Since observable properties can be updated at runtime:

dart
// Toggle snap-to-grid
controller.config.toggleSnapping();

// Update specific property
controller.config.snapToGrid.value = true;

// Batch update multiple properties
controller.config.update(
  snapToGrid: true,
  gridSize: 25.0,
);
dart
// Toggle both node and annotation snapping
controller.config.toggleSnapping();

// Toggle only node snapping
controller.config.toggleNodeSnapping();

// Toggle only annotation snapping
controller.config.toggleAnnotationSnapping();
dart
// Access plugins via controller
controller.minimap?.toggle();
controller.minimap?.setPosition(MinimapPosition.topRight);

controller.autoPan?.disable();
controller.autoPan?.useFast();

controller.debug?.toggle();
controller.debug?.setMode(DebugMode.spatialIndex);

AutoPanPlugin

The AutoPanPlugin manages automatic viewport panning when dragging elements near the edges of the viewport.

How Autopan Works

When you drag an element near the edge of the viewport, the canvas automatically pans to reveal more space. This allows seamless dragging across large canvases without manually panning.

AutoPanPlugin Constructor

dart
AutoPanPlugin({
  bool enabled = true,
  EdgeInsets edgePadding = const EdgeInsets.all(50.0),
  double panAmount = 10.0,
  Duration panInterval = const Duration(milliseconds: 16),
  bool useProximityScaling = false,
  Curve? speedCurve,
})

Properties

PropertyTypeDefaultDescription
enabledbooltrueWhether autopan is enabled
edgePaddingEdgeInsetsEdgeInsets.all(50.0)Distance from viewport edges where autopan activates
panAmountdouble10.0Base pan amount per tick in graph units
panIntervalDuration16msTime between pan ticks (~60fps)
useProximityScalingboolfalseScale speed based on proximity to edge
speedCurveCurve?nullEasing curve for proximity scaling

Preset Configurations

AutoPanPlugin provides three preset methods for common use cases:

dart
// Balanced settings for most use cases (default)
final plugin = AutoPanPlugin();
plugin.useNormal();
// Sets:
//   edgePadding: EdgeInsets.all(50.0)
//   panAmount: 10.0
//   panInterval: Duration(milliseconds: 16)
dart
// Faster panning for large canvases
final plugin = AutoPanPlugin();
plugin.useFast();
// Sets:
//   edgePadding: EdgeInsets.all(60.0)
//   panAmount: 20.0
//   panInterval: Duration(milliseconds: 12)
dart
// Slower, more controlled panning
final plugin = AutoPanPlugin();
plugin.usePrecise();
// Sets:
//   edgePadding: EdgeInsets.all(30.0)
//   panAmount: 5.0
//   panInterval: Duration(milliseconds: 20)

You can specify different padding for each edge:

dart
AutoPanPlugin(
  edgePadding: EdgeInsets.only(
    left: 50.0,
    right: 50.0,
    top: 30.0,
    bottom: 80.0,  // Larger to avoid bottom toolbar
  ),
  panAmount: 10.0,
)

Proximity Scaling

Enable proximity scaling for gradual speed increase as the pointer approaches the edge:

dart
AutoPanPlugin(
  edgePadding: EdgeInsets.all(50.0),
  panAmount: 15.0,
  useProximityScaling: true,
  speedCurve: Curves.easeIn,  // Slow start, fast finish
)

Available curves:

  • Curves.linear - Constant speed increase (default when null)
  • Curves.easeIn - Slow start, fast finish (recommended for precision)
  • Curves.easeInQuad - More gradual acceleration
dart
// Option 1: Disable in constructor
NodeFlowConfig(
  plugins: [
    AutoPanPlugin(enabled: false),
  ],
)

// Option 2: Disable at runtime via plugin
controller.autoPan?.disable();
dart
// Access via controller plugin
if (controller.autoPan?.isEnabled ?? false) {
  // Autopan is active
}

// Access current settings
final panAmount = controller.autoPan?.panAmount;
final edgePadding = controller.autoPan?.edgePadding;

Runtime Configuration

Change autopan settings at runtime:

dart
// Switch to a preset
controller.autoPan?.useNormal();
controller.autoPan?.useFast();
controller.autoPan?.usePrecise();

// Update individual properties
controller.autoPan?.setEdgePadding(EdgeInsets.all(60.0));
controller.autoPan?.setPanAmount(15.0);
controller.autoPan?.setPanInterval(Duration(milliseconds: 20));
controller.autoPan?.setUseProximityScaling(true);
controller.autoPan?.setSpeedCurve(Curves.easeIn);

// Enable/disable
controller.autoPan?.enable();
controller.autoPan?.disable();
controller.autoPan?.toggle();

DebugPlugin

The DebugPlugin provides debug visualization overlays for understanding internal editor state.

Enable debug mode via plugin configuration:

dart
NodeFlowConfig(
  plugins: [
    DebugPlugin(mode: DebugMode.all),
  ],
)

Debug Modes

ModeDescription
DebugMode.noneNo debug visualizations (default)
DebugMode.allShow all debug visualizations
DebugMode.spatialIndexShow only spatial index grid
DebugMode.autoPanZoneShow only autopan edge zones

Debug mode shows:

  • Spatial index grid: Visualization of the spatial partitioning used for hit testing
  • Autopan edge zones: Highlighted areas where autopan activates

Toggle at runtime via plugin:

dart
// Toggle between none and all
controller.debug?.toggle();

// Set specific mode
controller.debug?.setMode(DebugMode.spatialIndex);

// Cycle through all modes
controller.debug?.cycle();

INFO

Debug mode is useful during development to understand hit testing and autopan behavior. Disable it in production for better performance.

Complete Example

dart
class ConfigurableEditor extends StatefulWidget {
  @override
  State<ConfigurableEditor> createState() => _ConfigurableEditorState();
}

class _ConfigurableEditorState extends State<ConfigurableEditor> {
  late final NodeFlowController<MyData, dynamic> controller;

  @override
  void initState() {
    super.initState();
    controller = NodeFlowController<MyData, dynamic>(
      config: NodeFlowConfig(
        // Grid snapping
        snapToGrid: true,
        snapAnnotationsToGrid: true,
        gridSize: 20.0,

        // Zoom limits
        minZoom: 0.25,
        maxZoom: 4.0,

        // Port connection snapping
        portSnapDistance: 12.0,

        // Plugins for additional features
        plugins: [
          // Minimap with custom settings
          MinimapPlugin(
            visible: true,
            interactive: true,
            position: MinimapPosition.bottomRight,
          ),

          // Autopan enabled with default settings
          AutoPanPlugin(),

          // Debug visualization (disabled by default)
          DebugPlugin(mode: DebugMode.none),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Toolbar with config toggles
        Observer(
          builder: (_) => Row(
            children: [
              ToggleButton(
                isSelected: controller.config.snapToGrid.value,
                onPressed: controller.config.toggleNodeSnapping,
                child: Text('Snap to Grid'),
              ),
              ToggleButton(
                isSelected: controller.minimap?.isVisible ?? false,
                onPressed: () => controller.minimap?.toggle(),
                child: Text('Minimap'),
              ),
              ToggleButton(
                isSelected: controller.debug?.isEnabled ?? false,
                onPressed: () => controller.debug?.toggle(),
                child: Text('Debug'),
              ),
            ],
          ),
        ),

        // Editor
        Expanded(
          child: NodeFlowEditor<MyData, dynamic>(
            controller: controller,
            theme: NodeFlowTheme.light,
            nodeBuilder: (context, node) => MyNodeWidget(node: node),
          ),
        ),
      ],
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

See Also