Skip to content

NoirsCodingCorner/graph_flow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GraphFlow

Screenshot

GraphFlow is a powerful and flexible Flutter package for building interactive node-based editors. It provides a highly customizable canvas with support for grid backgrounds, dynamic node positioning, and a range of connection rendering styles with advanced pan & zoom functionalities. Build flowcharts, diagram editors, visual programming environments, and more – all with ease!

Pub Version
Flutter Platform

Example Usecase:

graph_flow_pretty

Features

  • Interactive Node Editor:
    Add, remove, and reposition node cards on a highly interactive canvas.
  • Dynamic Connections:
    Draw connections between nodes using customizable styles such as Bezier curves, straight lines, and more.
  • Advanced Pan & Zoom:
    Navigate your canvas easily using built-in support for panning and zooming with InteractiveViewer.
  • Customizable Grid Background:
    Configure grid spacing, colors, and line widths to suit your visual style.
  • Scene Persistence:
    Save and load entire scenes—including nodes, connections, and canvas offsets—via JSON for easy sharing and persistence.
  • Flexible Event Handling:
    Customize interactions with support for mouse and gesture callbacks.
  • Easy Integration:
    Extend the package with custom painters and node factories for bespoke node behaviors.

Example of a customized Editor

Gifshowcase

Getting Started

Installation

Add GraphFlow to your Flutter project's pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  graph_flow: ^0.1.0

Then run:

flutter pub get

Basic Usage

Below is a simple example that demonstrates how to integrate GraphFlow into your Flutter app. This sample creates a manager, adds two nodes, and displays the canvas with a grid and connection layer.

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:graph_flow/graph_flow.dart'; // Use your package's public API.
import 'package:graph_flow/src/connection_painter.dart';
import 'package:graph_flow/src/example_node.dart';
import 'package:graph_flow/src/manager.dart';
import 'package:graph_flow/src/node_canvas.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  static int _uniqueCounter = 0;
  
  static String generateUniqueId() {
    _uniqueCounter++; 
    // Create a unique id combining a timestamp and counter.
    return '${DateTime.now().millisecondsSinceEpoch}-$_uniqueCounter';
  }
  
  const MyApp({Key? key}) : super(key: key);
  
  String getNewID() => generateUniqueId();
  
  @override
  Widget build(BuildContext context) {
    Manager manager = Manager(getNewID: getNewID);
    // Register a node type factory.
    manager.nodeFactories['ExampleNode'] = ExampleNode.fromJson;
    // Add example nodes to the manager.
    manager.addNode(ExampleNode(manager: manager, id: getNewID()));
    manager.addNode(ExampleNode(manager: manager, id: getNewID()));
    
    return MaterialApp(
      title: 'GraphFlow Demo',
      home: Scaffold(
        backgroundColor: Colors.black,
        body: Stack(
          children: [
            // Main canvas with grid and nodes.
            CanvasPage(
              manager: manager, 
              gridSpacing: 10, 
              connectionPainter: ConnectionPainter(
                manager, 
                drawingType: ConnectionDrawingType.bezier,
              ),
            ),
            // UI controls to print or input JSON.
            Align(
              alignment: Alignment.bottomRight,
              child: Builder(
                builder: (context) => Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    IconButton(
                      onPressed: () {
                        Map<String, dynamic> json = manager.saveSceneToJson();
                        print(
                          const JsonEncoder.withIndent('  ').convert(json),
                        );
                      },
                      icon: const Icon(Icons.print, color: Colors.white),
                    ),
                    IconButton(
                      onPressed: () {
                        final TextEditingController controller =
                            TextEditingController();
                        showDialog(
                          context: context,
                          builder: (context) {
                            return AlertDialog(
                              title: const Text('Input JSON'),
                              content: TextField(
                                controller: controller,
                                maxLines: null,
                                decoration: const InputDecoration(
                                  hintText: 'Enter JSON here',
                                ),
                              ),
                              actions: [
                                TextButton(
                                  onPressed: () => Navigator.of(context).pop(),
                                  child: const Text('Cancel'),
                                ),
                                TextButton(
                                  onPressed: () {
                                    final inputJson = jsonDecode(controller.text);
                                    manager.loadSceneFromJson(inputJson);
                                    Navigator.of(context).pop();
                                  },
                                  child: const Text('OK'),
                                ),
                              ],
                            );
                          },
                        );
                      },
                      icon: const Icon(Icons.input, color: Colors.white),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Advanced Usage

GraphFlow is fully extensible. You can provide your own custom connection painters, override default callbacks for mouse and gesture events, or extend node card functionalities. For example, to use a custom connection painter:

class MyCustomPainter extends CustomPainter {
  final Manager manager;

  MyCustomPainter(this.manager);

  @override
  void paint(Canvas canvas, Size size) {
    // Your custom connection rendering logic.
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

// Usage in CanvasPage:
CanvasPage(
  manager: manager,
  connectionPainter: MyCustomPainter(manager),
);

Canvas Icon Customizable Features of CanvasPage

  • Manager

    • The required Manager instance controls nodes, connection points, and overall scene state.
  • Custom Connection Painter

    • Specify a custom painter via the connectionPainter parameter.
    • If not provided, the default ConnectionPainter is used to render connection lines.
  • Mouse Region Callbacks

    • onMouseEnter: Triggered when the mouse enters the canvas area.
    • onMouseHover: Updates the manager’s mouse position and handles hover events.
    • onMouseExit: Triggered when the mouse leaves the canvas area.
  • Gesture Detector Callbacks

    • onTapDown, onTapUp, onTap: Customize how tap events are handled.
    • onLongPress: Customize long-press behavior.
    • onPanStart, onPanUpdate, onPanEnd: Handle drag (panning) events to move nodes or navigate the canvas.
  • Canvas Dimensions

    • canvasWidth & canvasHeight: Define the size of the canvas.
  • Zoom & Pan Settings

    • maxZoom & minZoom: Control the zooming capabilities of the canvas.
    • scaleFactor: Factor applied to the scaling transformation.
  • Grid Settings

    • gridSpacing: Specifies the distance between grid lines.
    • lineColor: Defines the color of the grid lines.
    • lineWidth: Sets the stroke width of the grid lines.
    • overflowSpacing: Adds extra spacing beyond the widget’s bounds to ensure complete grid coverage.

connectionIcon Customizable Features of ConnectionPainter

- **Mouse Line Activation:** Toggle the visibility of a dynamic connection line from the selected connection point to the current mouse position using the `mouseLineActive` flag.
  • Drawing Type:
    Choose from a variety of connection drawing styles via the drawingType parameter:

    • bezier – Draw a bezier curve with vertical control points.
    • straightLine – Draw a simple straight line.
    • verticalThenHorizontal – Draw a line going vertically then horizontally.
    • halfHorizontalThenVertical – Draw a path going half horizontally then vertically.
    • halfVerticalThenHorizontal – Draw a path going half vertically then horizontally.
    • bezierHorizontalThenVertical – Draw a bezier curve transitioning horizontally then vertically.
  • Mouse Line Color:
    Customize the color of the mouse-tracking connection line through the mouseLineColor property.

  • Line Thickness:
    Adjust the stroke width of the connection lines with the lineThickness setting.

  • Endpoint Radius:
    Specify the radius for the endpoint dots on connection points using the endpointRadius.

Leverage these properties to fine-tune the visual style and interaction behavior of your connection lines for building highly interactive node-based editors.

Contributing

Contributions are very welcome and will be reviewed in sight!

License

GraphFlow is licensed under the MIT License. See the LICENSE file for details.

Outlook

GraphFlow is currently fresh in development. If you have any comments or wishes for this library feel free to contact me over the github or just leave a note in the flutter discord channel.

Plans:

  • Data Pipes: It is planned to add runtime data passing into the connections themselves to allow easier usage during runtime
  • More customizable Events: Events like creation, deletion and dragging of connections is to be made fully costumizable

Thank you all for using my library <3

About

A visual editor for modern workflows.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages