luke_flow_diagram 0.1.0 copy "luke_flow_diagram: ^0.1.0" to clipboard
luke_flow_diagram: ^0.1.0 copied to clipboard

A customizable flow diagram canvas for Flutter, inspired by React Flow.

example/lib/main.dart

import 'dart:convert';
import 'package:example/data.dart';
import 'package:flutter/material.dart';
import 'package:luke_flow_diagram/luke_flow_diagram.dart';

import 'utils.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      themeMode: ThemeMode.dark,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: Scaffold(
        backgroundColor: const Color.fromARGB(255, 46, 46, 53),
        body: const LukeFlowDiagram(),
      ),
    );
  }
}

class LukeFlowDiagram extends StatefulWidget {
  final double? width;
  final double? height;
  const LukeFlowDiagram({super.key, this.width, this.height});

  @override
  State<LukeFlowDiagram> createState() => _LukeFlowDiagramState();
}

class _LukeFlowDiagramState extends State<LukeFlowDiagram> {
  List<EdgeConnectionsModel> connections = [];
  late final nodes = List.generate(5, (index) => index).map((i) {
    final nodeId = UniqueKey().toString();

    return NodeModel(
      id: nodeId,
      inputSockets: [
        NodeSocketModel(
          connectionLimit: 1,
          nodeId: nodeId,
          id: UniqueKey().toString(),
          type: NodeSocketType.input,
          position: Vector2.zero,
          data: {},
        ),
      ],
      outputSockets: [
        NodeSocketModel(
          connectionLimit: 2,
          nodeId: nodeId,
          id: UniqueKey().toString(),
          type: NodeSocketType.output,
          position: Vector2.zero,
          data: {},
        ),
      ],
      data: DataModelExample(
        id: '$i',
        name: 'Node $i',
        description: 'This is the first node',
      ),
      position: getRandomPositionNearCenter(spread: 1000),
    );
  }).toList();

  final controller = LukeFlowCanvasController<DataModelExample>();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width ?? MediaQuery.of(context).size.width,
      height: widget.height ?? MediaQuery.of(context).size.height,
      child: Column(
        children: [
          Container(
            color: const Color.fromARGB(255, 44, 42, 48),
            child: Row(
              children: [
                TextButton(
                  onPressed: () {
                    controller.centerCanvas();
                  },
                  child: Text("Center Nodes"),
                ),
                TextButton(
                  onPressed: () {
                    final nodeId = UniqueKey().toString();
                    controller.addNode(
                      NodeModel(
                        id: nodeId,
                        position: getRandomPositionNearCenter(spread: 1000),
                        inputSockets: [
                          NodeSocketModel(
                            connectionLimit: 1,
                            nodeId: nodeId,
                            id: UniqueKey().toString(),
                            type: NodeSocketType.input,
                            position: Vector2.zero,
                            data: {},
                          ),
                        ],
                        outputSockets: [
                          NodeSocketModel(
                            connectionLimit: 2,
                            nodeId: nodeId,
                            id: UniqueKey().toString(),
                            type: NodeSocketType.output,
                            position: Vector2.zero,
                            data: {},
                          ),
                        ],
                        data: DataModelExample(
                          id: '${nodes.length}',
                          name: 'Node ${nodes.length}',
                          description: 'This is the first node',
                        ),
                      ),
                    );
                  },
                  child: Text("Add node"),
                ),
                TextButton(
                  onPressed: () {
                    final result = controller.toJson();
                    debugPrint(jsonEncode(result));
                  },
                  child: Text("Export"),
                ),
                TextButton(
                  onPressed: () {
                    controller.fromJson(diagramJson);
                  },
                  child: Text("Inport"),
                ),
              ],
            ),
          ),
          Expanded(
            child: LukeFlowCanvas<DataModelExample>(
              controller: controller,
              nodes: nodes,
              initialConnections: connections,
              onEdgeDrop: (source, dropPosition) {
                /// You can create a new node when you drop the connection edge on the canvas by using the onEdgeDrop .
                final nodeId = UniqueKey().toString();

                /// Create new sockets for the new node
                final inputSocket = NodeSocketModel(
                  nodeId: nodeId,
                  position: Vector2.zero,
                  type: NodeSocketType.input,
                );
                final outputSocket = NodeSocketModel(
                  nodeId: nodeId,
                  position: Vector2.zero,
                  type: NodeSocketType.output,
                );

                controller.addNodes([
                  NodeModel(
                    id: nodeId,
                    position: dropPosition,
                    inputSockets: [inputSocket],
                    outputSockets: [outputSocket],
                    data: DataModelExample(
                      id: '${nodes.length}',
                      name: 'Node ${nodes.length}',
                      description: 'This is the first node',
                    ),
                  ),
                ]);

                /// Wait for the node to be added before creating the connection
                Future.delayed(Duration(milliseconds: 100), () {
                  controller.addConnection(
                    EdgeConnectionsModel(
                      source: source,
                      target: source.type == NodeSocketType.input
                          ? outputSocket
                          : inputSocket,
                    ),
                  );

                  /// Trigger a manual update to force the edges to update
                  controller.updateNodesPosition(nodes);
                });
              },
              onConnectionError: (connection) {
                /// This function can be used to handle connection limit error
                debugPrint(
                  "ERROR CONNECTING ${connection.source.id} to ${connection.target.id}",
                );
              },
              nodeBuilder: (node) {
                return Container(
                  padding: const EdgeInsets.all(16),
                  decoration: BoxDecoration(
                    color: node.data?.color ?? Colors.white,
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: Center(
                    child: Text(
                      node.data?.name ?? 'Node',
                      style: TextStyle(color: Colors.black),
                    ),
                  ),
                );
              },
              onUpdate: (n, c) {
                connections = c;
              },
            ),
          ),
        ],
      ),
    );
  }
}

class DataModelExample {
  final String id;
  final String name;
  final String description;
  final Color? color;

  DataModelExample({
    this.color,
    required this.id,
    required this.name,
    required this.description,
  });

  Map<String, dynamic> toJson() {
    return {'id': id, 'name': name, 'description': description};
  }

  DataModelExample.fromJson(Map<String, dynamic> json)
    : id = json['id'],
      name = json['name'],
      description = json['description'],
      color = json['color'] != null ? Color(json['color']) : null;
}
7
likes
0
points
17
downloads

Publisher

verified publisherluk3d.com

Weekly Downloads

A customizable flow diagram canvas for Flutter, inspired by React Flow.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on luke_flow_diagram