Interactive Flowchart Builder in React
This challenge asks you to build a simple, interactive flowchart builder using React and TypeScript. The goal is to create a visual editor where users can drag and drop flowchart nodes (e.g., Start, Process, Decision, End) onto a canvas, connect them with arrows, and rearrange the diagram. This is a common UI element in many applications, and building one from scratch provides valuable experience in component design, state management, and event handling.
Problem Description
You are tasked with creating a React component that allows users to build flowcharts visually. The component should provide a canvas where nodes can be placed and connected. The user interface should allow for adding, deleting, moving, and connecting nodes. The flowchart should be represented internally as a data structure that can be easily serialized and deserialized (e.g., JSON).
Key Requirements:
- Node Types: Support at least four node types: "Start," "Process," "Decision," and "End." Each node type should have a distinct visual representation (e.g., different shapes or colors).
- Drag and Drop: Users should be able to drag nodes from a palette onto the canvas.
- Canvas Placement: Nodes should be placed on the canvas at the mouse cursor's location when dropped.
- Node Movement: Users should be able to drag existing nodes on the canvas to reposition them.
- Connections: Users should be able to draw connections (arrows) between nodes. Clicking on a node should allow the user to initiate a connection to another node.
- Data Structure: Maintain an internal data structure (e.g., an array of node objects) to represent the flowchart. Each node object should include its type, position (x, y coordinates), and connections (an array of node IDs it connects to).
- Visual Representation: The flowchart should be visually appealing and easy to understand.
- Clearance: Nodes should not overlap. When a node is dragged, it should be repositioned to the nearest available spot on the canvas.
Expected Behavior:
- A palette of available node types (Start, Process, Decision, End) is displayed.
- Dragging a node from the palette onto the canvas creates a new node of that type at the mouse cursor's location.
- Clicking a node and then clicking another node creates a connection (arrow) between them.
- Dragging an existing node on the canvas moves it to a new location, ensuring it doesn't overlap with other nodes.
- Deleting a node removes it from the canvas and breaks any connections to it.
- The flowchart data structure is updated whenever a node is added, deleted, moved, or connected.
Edge Cases to Consider:
- Overlapping Nodes: Implement logic to prevent nodes from overlapping. Reposition nodes when dragged to avoid overlaps.
- Invalid Connections: Prevent connections between nodes of the same type (e.g., Start to Start). Consider allowing connections between all node types.
- Deleting Nodes with Connections: Handle the deletion of nodes that have incoming or outgoing connections gracefully. Remove the connections from other nodes.
- Large Flowcharts: Consider performance implications when dealing with a large number of nodes and connections.
- Canvas Boundaries: Prevent nodes from being dragged outside the canvas boundaries.
Examples
Example 1:
Input: Initial empty canvas, palette with Start, Process, Decision, End nodes. User drags a "Start" node and a "Process" node onto the canvas, then connects the "Start" node to the "Process" node.
Output: A flowchart with a "Start" node and a "Process" node connected by an arrow. The "Start" node should be the source of the connection, and the "Process" node should be the target.
Explanation: The user interaction creates two nodes and a connection between them, updating the internal data structure to reflect this.
Example 2:
Input: Canvas with a "Start" node, a "Process" node, and a "Decision" node. User drags the "Process" node to a new location on the canvas.
Output: The "Process" node is moved to the new location, and the connection between the "Start" node and the "Process" node is updated to reflect the new position. No overlapping nodes are present.
Explanation: The node's position is updated in the internal data structure, and the visual representation is redrawn.
Example 3:
Input: Canvas with a "Start" node connected to a "Process" node, and the "Process" node connected to a "Decision" node. User deletes the "Process" node.
Output: The "Process" node is removed from the canvas. The connection between the "Start" node and the "Process" node is removed. The "Decision" node remains on the canvas.
Explanation: The node is removed from the internal data structure, and the connections to it are also removed from other nodes.
Constraints
- Node Size: Each node should have a fixed size of 80x80 pixels.
- Canvas Size: The canvas should be 800x600 pixels.
- Connection Lines: Connection lines should be straight lines.
- Performance: The component should render smoothly even with 20+ nodes. Avoid unnecessary re-renders.
- Data Structure: The internal data structure should be easily serializable to JSON.
Notes
- You can use any React library for drag and drop functionality (e.g.,
react-dnd,react-beautiful-dnd), but you are not required to. Implementing the drag and drop logic manually is also acceptable. - Focus on the core functionality of adding, deleting, moving, and connecting nodes. Advanced features like zooming, panning, or exporting to image formats are not required.
- Consider using a state management library like Zustand or Recoil for managing the flowchart data, but it is not mandatory. React's
useStateanduseReducerare sufficient for this challenge. - Prioritize clean, readable code and a well-structured component architecture.
- Think about how to efficiently update the visual representation of the flowchart when the internal data structure changes.