Interactive Whiteboard Canvas in React with TypeScript
This challenge asks you to build a basic interactive whiteboard canvas within a React application using TypeScript. The whiteboard should allow users to draw freehand using their mouse or touch input, with basic functionalities like clearing the canvas. This is a common feature in collaborative tools and online learning platforms, and understanding how to implement it is a valuable skill.
Problem Description
You are tasked with creating a React component that renders an HTML5 canvas element and allows users to draw on it. The component should handle mouse/touch events to track drawing input and update the canvas accordingly. The drawing should be persistent within the component's state, meaning the canvas content is preserved as long as the component is mounted. You must also implement a "Clear" button that clears the canvas.
Key Requirements:
- Canvas Rendering: The component must render an HTML5 canvas element.
- Drawing Functionality: Users should be able to draw freehand on the canvas using their mouse or touch input. The drawing should be continuous, not just single clicks.
- Clear Canvas: A "Clear" button should be provided that, when clicked, clears the canvas content.
- State Management: The drawing data (e.g., a list of points or paths) should be managed within the component's state.
- TypeScript: The entire solution must be written in TypeScript.
Expected Behavior:
- When the component mounts, the canvas should be empty.
- As the user draws, lines should appear on the canvas, following the mouse/touch movements.
- Clicking the "Clear" button should erase all drawings from the canvas.
- The canvas should redraw its contents when the component re-renders (e.g., after clearing).
Edge Cases to Consider:
- Canvas Resizing: The canvas should ideally maintain its aspect ratio and redraw correctly if the window is resized. (This is a bonus, not a strict requirement for the initial solution).
- Performance: Drawing many points can impact performance. Consider strategies to optimize drawing updates (e.g., debouncing or throttling).
- Mobile Devices: Ensure the drawing functionality works smoothly on touch devices.
- Empty Canvas: Handle the case where the canvas is initially empty and the user starts drawing.
Examples
Example 1:
Input: User draws a simple line from the top-left to the bottom-right of the canvas.
Output: A line is drawn on the canvas, connecting the starting and ending points of the mouse movement.
Explanation: The component tracks mouse movement and draws a line segment between consecutive points.
Example 2:
Input: User draws a circle on the canvas.
Output: A circular shape is drawn on the canvas, following the user's mouse movement.
Explanation: The component continuously draws line segments to approximate the circular shape.
Example 3: (Edge Case)
Input: User rapidly moves the mouse across the canvas.
Output: A continuous line is drawn, even with rapid mouse movements.
Explanation: The component should handle rapid input without significant lag or dropped points.
Constraints
- Canvas Size: The canvas should be initially 500px wide and 400px high.
- Line Width: The line width for drawing should be 2px.
- Line Color: The line color should be black.
- Performance: The drawing updates should be reasonably smooth (aim for at least 30 frames per second). While optimization is encouraged, it's not the primary focus of this challenge.
- Dependencies: You are allowed to use standard React and TypeScript features. No external libraries are permitted for this initial implementation.
Notes
- Consider using the
useStatehook to manage the drawing data. - The
onMouseDown,onMouseMove,onMouseUp,onTouchStart,onTouchMove, andonTouchEndevent handlers will be crucial for capturing user input. - The
clearRect()method of the canvas context can be used to clear the canvas. - Think about how to represent the drawing data efficiently (e.g., as an array of points, or as a series of paths).
- Focus on the core drawing functionality and the "Clear" button first. Canvas resizing and advanced optimization can be considered as extensions.