Have you ever needed to create an interactive diagram editor in your React application? Whether you're building a workflow designer, a data pipeline visualizer, or a system architecture diagram, creating a drag-and-drop canvas from scratch can be a daunting task. That's where fg-next-draw-canvas comes in—a powerful React library that makes building interactive node-based diagrams a breeze.
What is fg-next-draw-canvas?
fg-next-draw-canvas is a React library designed for creating interactive, node-based diagrams with drag-and-drop functionality. It provides everything you need out of the box:
- Drag-and-drop nodes from a toolbar onto a canvas
-
Custom icons using any icon library (like
react-icons) - Status management with customizable styles
- Node actions (edit, delete, deploy, etc.)
- Connection system to link nodes together
- Event system for reactivity and state synchronization
- Zoom controls for navigating large diagrams
The library is built with flexibility in mind, using strategy patterns that allow you to customize almost every aspect of the rendering and behavior.
Quick Start
Getting started is straightforward. Install the package:
npm install fg-next-draw-canvas
Then set up the basic components:
import React from 'react';
import {
FgnDrawCanvasComponent,
FgnToolbarComponent,
FgnZoomComponent,
} from 'fg-next-draw-canvas';
function App() {
return (
<div>
<FgnToolbarComponent/>
<FgnDrawCanvasComponent/>
<FgnZoomComponent/>
</div>
);
}
export default App;
That's it! You now have a fully functional canvas with a toolbar. But the real power comes from customization.
Practical Examples
Let's dive into some real-world scenarios that showcase the library's flexibility.
Example 1: Custom Icons with react-icons
One of the first things you'll want to customize is the icons. The library uses an IconStrategy pattern that lets you map icon codes to React components.
Here's how you can integrate icons from react-icons:
import { IconStrategy } from 'fg-next-draw-canvas';
import { BsBucket } from 'react-icons/bs';
import { SiApachekafka } from 'react-icons/si';
import { SiApacheflink } from 'react-icons/si';
const customIconStrategy: IconStrategy = {
getIcon: (code?: string) => {
switch (code) {
case 's3-bucket':
return React.createElement(BsBucket as any);
case 'msk-topic':
return React.createElement(SiApachekafka as any);
case 'flink-sql':
return React.createElement(SiApacheflink as any);
default:
return undefined;
}
}
};
<FgnDrawCanvasComponent iconStrategy={customIconStrategy} />
This pattern makes it easy to use icons from any library or even create your own custom icon components.
Example 2: Status Management with Custom Styles
If you're building a system that tracks deployment states or workflow statuses, you'll love the StatusStrategy. It allows you to define custom styles for different node statuses.
import { StatusStrategy } from 'fg-next-draw-canvas';
const customStatusStrategy: StatusStrategy = {
defaultStatus: 'draft',
getStyle: (status: string) => {
switch (status) {
case 'draft':
return {
backgroundColor: '#E0E0E0',
textColor: '#666',
borderColor: '#BDBDBD'
};
case 'ready':
return {
backgroundColor: '#2196F3',
textColor: 'white',
borderColor: '#1976D2'
};
case 'deploying':
return {
backgroundColor: '#FF9800',
textColor: 'white',
borderColor: '#F57C00'
};
case 'running':
return {
backgroundColor: '#4CAF50',
textColor: 'white',
borderColor: '#388E3C'
};
case 'failed':
return {
backgroundColor: '#F44336',
textColor: 'white',
borderColor: '#D32F2F'
};
default:
return {
backgroundColor: '#E0E0E0',
textColor: '#666',
borderColor: '#BDBDBD'
};
}
}
};
<FgnDrawCanvasComponent statusStrategy={customStatusStrategy} />
This is perfect for visualizing the state of your infrastructure, workflows, or any system where nodes have lifecycle states.
Example 3: Interactive Node Actions
What makes a diagram truly interactive? Actions! You can add custom buttons to each node that trigger specific behaviors.
import { FgnNodeAction } from 'fg-next-draw-canvas';
import { TbEdit, TbTrash } from 'react-icons/tb';
import { IoRocketSharp } from 'react-icons/io5';
import { FaPlay } from 'react-icons/fa';
const customNodeActions: FgnNodeAction[] = [
{
id: 'Delete',
label: React.createElement(TbTrash as any),
onClick: (nodeId: string) => {
console.log('Delete node:', nodeId);
// Your delete logic here
},
order: 1,
borderColor: 'red',
iconColor: 'red',
backgroundColor: '#ffffff'
},
{
id: 'Edit',
label: React.createElement(TbEdit as any),
onClick: (nodeId: string) => {
console.log('Edit node:', nodeId);
// Open edit modal, navigate to editor, etc.
},
order: 2,
borderColor: 'blue',
iconColor: 'blue',
backgroundColor: '#ffffff'
},
{
id: 'Deploy',
label: React.createElement(IoRocketSharp as any),
onClick: (nodeId: string) => {
console.log('Deploy node:', nodeId);
// Trigger deployment
},
order: 3,
borderColor: 'black',
iconColor: 'black',
backgroundColor: '#ffffff'
},
{
id: 'Start',
label: React.createElement(FaPlay as any),
onClick: (nodeId: string) => {
console.log('Start node:', nodeId);
// Start the service
},
order: 4,
borderColor: 'green',
iconColor: 'green',
backgroundColor: '#ffffff'
}
];
<FgnDrawCanvasComponent
nodeActions={customNodeActions}
maxVisibleActions={2}
/>
The maxVisibleActions prop automatically groups excess actions into a dropdown menu, keeping your UI clean while maintaining full functionality.
Example 4: Reacting to Events
The event system is where the library really shines for building reactive applications. You can listen to canvas operations and sync with your backend, update local state, or trigger side effects.
import { useFgnEventListener, CANVAS_EVENTS } from 'fg-next-draw-canvas';
function MyComponent() {
// Listen for new nodes
useFgnEventListener(CANVAS_EVENTS.NODE_ADDED, (node) => {
console.log('Node added:', node);
// Sync with backend
saveNodeToBackend(node);
});
// Listen for node updates (e.g., after dragging)
useFgnEventListener(CANVAS_EVENTS.NODE_UPDATED, (node) => {
console.log('Node updated:', node);
// Update backend with new position
updateNodePosition(node.id, node.x, node.y);
});
// Listen for connections
useFgnEventListener(CANVAS_EVENTS.CONNECTION_CREATED, (connection) => {
console.log('Connection created:', connection);
// Create relationship in your data model
createRelationship(connection.sourceNodeId, connection.targetNodeId);
});
// Listen for deletions
useFgnEventListener(CANVAS_EVENTS.CONNECTION_DELETED, (connection) => {
console.log('Connection deleted:', connection);
// Remove relationship
deleteRelationship(connection.id);
});
return (
<div>
<FgnDrawCanvasComponent />
{/* Your other components */}
</div>
);
}
The library provides several events:
-
NODE_ADDED- When a node is created -
NODE_UPDATED- When a node's position or properties change -
CONNECTION_CREATED- When two nodes are connected -
CONNECTION_DELETED- When a connection is removed -
NODES_REPLACED- When all nodes are replaced -
NODE_REPLACED- When a single node is replaced
This event-driven architecture makes it easy to keep your canvas state synchronized with your backend or state management system.
Example 5: Complete Real-World Setup
Let's put it all together in a practical example—a data pipeline designer:
import React from 'react';
import {
FgnDrawCanvasComponent,
FgnToolbarComponent,
FgnZoomComponent,
useFgnEventListener,
CANVAS_EVENTS,
FgnToolbarItem,
FgnNodeAction,
} from 'fg-next-draw-canvas';
import type { IconStrategy, StatusStrategy } from 'fg-next-draw-canvas';
import { SiApacheflink, SiApachekafka } from 'react-icons/si';
import { BsBucket } from 'react-icons/bs';
import { TbEdit, TbTrash } from 'react-icons/tb';
import { IoRocketSharp } from 'react-icons/io5';
import { FaPlay } from 'react-icons/fa';
// Custom icon strategy
const iconStrategy: IconStrategy = {
getIcon: (code?: string) => {
switch (code) {
case 's3-bucket':
return React.createElement(BsBucket as any);
case 'msk-topic':
return React.createElement(SiApachekafka as any);
case 'flink-sql':
return React.createElement(SiApacheflink as any);
default:
return undefined;
}
}
};
// Status strategy for pipeline states
const statusStrategy: StatusStrategy = {
defaultStatus: 'draft',
getStyle: (status: string) => {
switch (status) {
case 'draft':
return { backgroundColor: '#E0E0E0', textColor: '#666', borderColor: '#BDBDBD' };
case 'ready':
return { backgroundColor: '#2196F3', textColor: 'white', borderColor: '#1976D2' };
case 'running':
return { backgroundColor: '#4CAF50', textColor: 'white', borderColor: '#388E3C' };
case 'failed':
return { backgroundColor: '#F44336', textColor: 'white', borderColor: '#D32F2F' };
default:
return { backgroundColor: '#E0E0E0', textColor: '#666', borderColor: '#BDBDBD' };
}
}
};
// Node actions
const nodeActions: FgnNodeAction[] = [
{
id: 'Edit',
label: React.createElement(TbEdit as any),
onClick: (nodeId: string) => openEditModal(nodeId),
order: 1,
borderColor: 'blue',
iconColor: 'blue',
backgroundColor: '#ffffff'
},
{
id: 'Deploy',
label: React.createElement(IoRocketSharp as any),
onClick: (nodeId: string) => deployPipeline(nodeId),
order: 2,
borderColor: 'black',
iconColor: 'black',
backgroundColor: '#ffffff'
},
{
id: 'Delete',
label: React.createElement(TbTrash as any),
onClick: (nodeId: string) => deleteNode(nodeId),
order: 3,
borderColor: 'red',
iconColor: 'red',
backgroundColor: '#ffffff'
}
];
// Toolbar items
const toolbarItems: FgnToolbarItem[] = [
{
id: '1',
code: 's3-bucket',
color: '#15ad0b',
label: 'S3 Bucket',
tooltip: 'Add S3 bucket as data source'
},
{
id: '2',
code: 'msk-topic',
color: '#830bc9',
label: 'MSK Topic',
tooltip: 'Add MSK Kafka topic'
},
{
id: '3',
code: 'flink-sql',
color: '#2344f5',
label: 'Flink SQL',
tooltip: 'Add Flink SQL transformation job'
}
];
const PipelineDesigner: React.FC = () => {
// Event listeners for state synchronization
useFgnEventListener(CANVAS_EVENTS.NODE_ADDED, (node) => {
saveToBackend('/api/nodes', node);
});
useFgnEventListener(CANVAS_EVENTS.NODE_UPDATED, (node) => {
updateBackend(`/api/nodes/${node.id}`, { x: node.x, y: node.y });
});
useFgnEventListener(CANVAS_EVENTS.CONNECTION_CREATED, (connection) => {
saveToBackend('/api/connections', connection);
});
return (
<div className="pipeline-designer">
<FgnToolbarComponent
items={toolbarItems}
iconStrategy={iconStrategy}
/>
<FgnDrawCanvasComponent
iconStrategy={iconStrategy}
statusStrategy={statusStrategy}
nodeActions={nodeActions}
maxVisibleActions={2}
/>
<FgnZoomComponent alignment="center" />
</div>
);
};
export default PipelineDesigner;
This example demonstrates how all the pieces fit together to create a production-ready diagram editor.
Use Cases
fg-next-draw-canvas is perfect for:
- Workflow Designers - Build visual workflow editors for your applications
- Data Pipeline Tools - Visualize and design data processing pipelines
- System Architecture Diagrams - Create interactive architecture visualizations
- Process Modeling - Design business processes with drag-and-drop
- Configuration UIs - Let users configure complex systems visually
- Educational Tools - Build interactive learning experiences
- Project Management - Visualize project dependencies and relationships
Why This Library?
You might be wondering: "Why not use D3.js or another canvas library?" While those are powerful tools, fg-next-draw-canvas offers:
- React-First Approach - Built specifically for React with hooks and components
- Low Boilerplate - Get started in minutes, not hours
- TypeScript Support - Full type safety out of the box
- Strategy Pattern Architecture - Highly customizable without modifying source code
- Event System - Built-in reactivity for easy state management
- Active Maintenance - Regular updates and community support
Getting Started Today
Ready to build your first interactive diagram? Here's what you need:
- Install the package:
npm install fg-next-draw-canvas
-
Check out the documentation:
Start with the basic example and gradually add customizations
Join the community - Report issues, suggest features, or contribute!
Conclusion
fg-next-draw-canvas is a powerful, flexible library that makes building interactive node-based diagrams in React straightforward. Whether you're building a simple workflow editor or a complex system designer, the library provides the building blocks you need while staying out of your way.
The combination of strategy patterns, comprehensive event system, and React-first design makes it a joy to work with. Give it a try in your next project!
Resources:
Have you built something cool with fg-next-draw-canvas? Share it in the comments below! I'd love to see what you create.
Tags: #react #typescript #diagrams #canvas #drag-and-drop #webdev #javascript #opensource
Top comments (0)