fldraw
A powerful, extensible, and high-performance infinite canvas and diagramming library for Flutter, inspired by tldraw and eraser.io
fldraw
provides a complete toolkit for building applications that require node-based editors, whiteboarding, or any kind of interactive canvas. It's built from the ground up with performance and customization in mind, using a custom rendering pipeline to ensure a smooth experience even with a large number of objects.
✨ Features
- Infinite Canvas: Pan and zoom on a limitless canvas.
- Rich Toolset: Pre-built tools for selection, shapes (rectangles, circles), arrows, lines, free-hand drawing, text, and figures.
- Node-Based System: Create complex nodes with custom headers, content, and editable fields.
- Smart Attachments: Arrows intelligently snap and attach to the borders of nodes and shapes.
- High Performance: Built on a custom
RenderObject
for efficient rendering and smooth interaction. - State Management with BLoC: A clear and predictable state management architecture.
- Powerful Controller API: Programmatically control the canvas, manage tools, and manipulate objects from your own widgets.
- Undo/Redo History: A robust, built-in history stack for all major actions.
- Keyboard Shortcuts: Speed up your workflow with intuitive keyboard shortcuts for tools and actions.
- Text-to-Diagram (fldraw-lang): A simple, text-based language to programmatically generate entire diagrams.
- Customizable UI: Use builders to completely customize the appearance of nodes, context menus, and more coming soon.
📖 Table of Contents
- Installation
- Quick Start
- Core Concepts
- Advanced Usage
- Contributing
- Star History
- Author
- Support the project
- License
📦 Installation
Add fldraw
to your pubspec.yaml
file:
dependencies:
fldraw: ^latest_version
Then, run flutter pub get
in your terminal.
🚀 Quick Start
Getting started with fldraw
is simple. Wrap your canvas area with the FlDraw
widget and provide it with an FlDrawCanvas
and a FlToolbar
.
import 'package:fldraw/fldraw.dart';
import 'package:flutter/material.dart';
class MyDiagramPage extends StatefulWidget {
const MyDiagramPage({super.key});
@override
State<MyDiagramPage> createState() => _MyDiagramPageState();
}
class _MyDiagramPageState extends State<MyDiagramPage> {
FlDrawController? controller;
@override
Widget build(BuildContext context) {
return Scaffold(
body: FlDraw(
// The onControllerCreated callback gives you access to the controller
// for programmatic interaction with the canvas.
onControllerCreated: (c) {
setState(() {
controller = c;
});
},
child: Stack(
alignment: Alignment.center,
children: [
// The main canvas widget
const FlDrawCanvas(debug: true), // Set debug to true for helpful overlays
// The toolbar for selecting tools
Positioned(
top: 24,
child: FlToolbar(svgs: const []), // svgs list is for a future feature
),
// A panel to show the undo/redo history
if (controller != null)
Positioned(
bottom: 24,
left: 24,
child: SizedBox(
height: 200,
width: 250,
child: Card(
child: HistoryPanel(controller: controller!),
),
),
),
],
),
),
);
}
}
🧠 Core Concepts
FlDraw
Widget
This is the root widget of the library. It sets up all the necessary BLoCs (CanvasBloc
, ToolBloc
, SelectionBloc
) and provides them to the widget tree. It is the entry point for using the library.
onControllerCreated
: A crucial callback that provides you with anFlDrawController
instance once the canvas is initialized.
FlDrawCanvas
This is the main widget that renders the infinite canvas, grid, nodes, and all drawing objects. It handles all user interactions like panning, zooming, and drawing.
debug
: When set totrue
, it displays useful information like the current viewport coordinates, zoom level, and selection count.
FlDrawController
The controller is your primary tool for interacting with the canvas programmatically. It provides a clean, high-level API to abstract away the underlying BLoC architecture.
- Streams: Listen to
canvasStateStream
,selectionStateStream
, andtoolStateStream
to react to changes. - Methods: Call methods like
undo()
,redo()
,setTool()
,addNode()
,zoomIn()
,centerView()
, andloadProject()
.
Toolbar & Tools
The FlToolbar
widget provides a ready-made UI for selecting the active tool. The canvas behavior changes based on the currently selected tool in the ToolBloc
. Keyboard shortcuts are also available to quickly switch between tools.
Tool | Shortcut | Description |
---|---|---|
Select | V |
Select, move, and resize objects. |
Rectangle | R |
Draw a rectangle shape. |
Circle | O |
Draw a circle/oval shape. |
Arrow | A |
Draw an arrow connecting two points. |
Line | L |
Draw a line. |
Pencil | D |
Draw a free-hand stroke. |
Text | T |
Create a text object. |
Figure | F |
Create a dashed group container. |
Modifier Keys for Enhanced Control
You can hold down modifier keys to enhance the behavior of tools and actions, providing more precise control over your creations.
Key(s) | Action | Description |
---|---|---|
Shift |
Draw Perfect Shapes | While drawing with the Rectangle or Circle tool, hold Shift to lock the aspect ratio, creating a perfect square or circle. |
Shift |
Draw Locked-Angle Lines/Arrows | While drawing with the Line or Arrow tool, hold Shift to snap the line to 45-degree angle increments (0°, 45°, 90°, etc.). |
Shift + Click |
Multi-Select | While using the Select tool, hold Shift and click on objects to add them to your current selection without deselecting others. |
Ctrl /Cmd + Click |
Multi-Select (Alternative) | Same as Shift + Click, allows for adding objects to the current selection. |
Shift + Ctrl /Cmd |
Draw Orthogonal Arrows | While drawing with the Arrow tool, hold both Shift and Ctrl /Cmd to create an orthogonal (right-angled) connector line. |
🛠️ Advanced Usage
Programmatic Control with FlDrawController
Once you have the controller from the onControllerCreated
callback, you can perform a wide variety of actions.
// Change the active tool to Rectangle
controller.setTool(EditorTool.square);
// Add a new node to the canvas
controller.addNode(
NodeInstance(
state: NodeState(),
offset: const Offset(100, 150),
heading: 'My First Node',
value: 'This was added from code!',
),
);
// Zoom out and center the view
controller.zoomOut();
controller.centerView();
Text-to-Diagram with FlDrawParser
fldraw
includes a powerful parser for a simple, text-based language to define entire diagrams. This is perfect for generating diagrams from code, versioning them in git, or building integrations.
void generateDiagramFromText() {
// 1. Define your diagram using fldraw-lang syntax
const myDiagramCode = """
// This is a comment
StartPoint [shape: circle, text: "Start"]
Decision [shape: node, heading: "Make a Choice"]
EndPoint [shape: rect, text: "End"]
// Define relationships
StartPoint -> Decision
Decision -> EndPoint
""";
// 2. Create a parser and generate the JSON
final parser = FlDrawParser();
final jsonString = parser.parse(myDiagramCode);
final projectData = jsonDecode(jsonString);
// 3. Load the generated project into the canvas
controller?.loadProject(projectData);
}
This will automatically parse the text, lay out the nodes, and render the complete diagram on the canvas.
Customizing Nodes
You can completely change the appearance of nodes by providing builder functions to the FlDrawCanvas
widget.
headerBuilder
: Customizes the header of a node.nodeBuilder
: Replaces the entire node widget with your own implementation, giving you full control.
FlDrawCanvas(
headerBuilder: (context, node, onToggleCollapse) {
// Return your own custom header widget here
return Container(
padding: const EdgeInsets.all(12),
color: Colors.deepPurple,
child: Row(
children: [
Icon(Icons.api, color: Colors.white),
const SizedBox(width: 8),
Text(
node.heading ?? 'Custom Node',
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
],
),
);
},
)
Roadmap & Future Features
fldraw
is under active development. My goal is to make it the most powerful and easy-to-use diagramming library for Flutter. Below is a list of planned features and improvements. Contributions are highly welcome!
☐ Style & Property Inspector: Implement a robust styling system (fill color, stroke, text properties) and a property panel widget to edit selected objects.
☐ Mobile & Touchscreen Enhancements: Add intuitive two-finger gestures like pinch-to-zoom and two-finger pan.
☐ Contextual Mobile UI: Create a "delete" button or menu that appears above selected objects for easier interaction on touch devices.
☐ Canvas Minimap: Add a small navigator view, similar to tldraw
, for a high-level overview and quick panning.
☐ Desktop-Style Menu Bar: Implement a classic menu bar (File
, Edit
, View
) with common actions like Export and a list of keyboard shortcuts.
☐ Enhanced Exporting: Add functionality to export the canvas as an image (PNG/SVG).
☐ Improved Example Project: Enhance the example application to demonstrate saving and loading project state to/from a file.
Contributing ❤️
Contributions are welcome and greatly appreciated! fldraw
is an open-source project, and we'd love to see it grow with the help of the community.
If you'd like to contribute, please feel free to:
- Report a bug: Create an issue detailing the problem you've encountered.
- Suggest a feature: Open an issue to discuss a new feature or enhancement.
- Submit a pull request:
- Fork the repository.
- Create a new branch for your feature (
git checkout -b feature/amazing-feature
). - Make your changes.
- Commit your changes (
git commit -m 'Add some amazing feature'
). - Push to the branch (
git push origin feature/amazing-feature
). - Open a Pull Request.
Star History
Author ✍️
This project is authored and maintained by Yash Makan.
Building software in public and sharing everything I learn along the way.
I am currently open looking for new job opportunities and interesting contract projects. If you are looking for a dedicated Flutter developer or have an exciting project in mind, please feel free to reach out 🙏
- Email: contact@yashmakan.com
- Website: yashmakan.com
- LinkedIn: linkedin.com/in/yashmakan
- GitHub: @yashmakan
- Cal.com: @yashmakan
Support The Project
If fldraw
has been useful to you, please consider giving it a ⭐️ on GitHub!
For those who wish to provide more direct support, you can:
Your support helps in the ongoing development and maintenance of the project. Thank you!
License 📜
fldraw
is released under the MIT License. See the LICENSE
file for more details.