Interactive Canvas Renderer in Vue with TypeScript
This challenge asks you to build a simple, interactive canvas renderer within a Vue component. The renderer should allow drawing basic shapes (circles and rectangles) onto the canvas using mouse events, and provide basic controls for shape properties like color and size. This is a useful exercise for understanding how to integrate canvas functionality with a reactive UI framework like Vue.
Problem Description
You need to create a Vue component that renders a canvas and allows the user to draw circles and rectangles on it using their mouse. The component should include the following features:
- Canvas Rendering: The component should create a canvas element and render shapes drawn by the user.
- Shape Selection: The user should be able to select between drawing circles and rectangles via buttons or a dropdown.
- Drawing Logic: Implement mouse event listeners (mousedown, mousemove, mouseup) to detect drawing actions. The drawing should start on
mousedownand continue untilmouseup. - Shape Properties: Provide controls (e.g., input fields or a color picker) to adjust the color and size (radius for circles, width/height for rectangles) of the shapes being drawn.
- Clear Canvas: Include a button to clear the canvas, removing all drawn shapes.
- Shape Storage: Store the drawn shapes in an array within the Vue component's data. Each shape should have properties like
type(circle or rectangle),x,y,radius(for circles),width(for rectangles),height(for rectangles), andcolor. - Redraw on Data Change: The canvas should redraw whenever the array of shapes changes (e.g., when a new shape is added or the canvas is cleared).
Expected Behavior:
- When the component loads, a canvas element is displayed.
- The user can select either "Circle" or "Rectangle" to draw.
- On
mousedown, drawing begins. The mouse coordinates are recorded. - On
mousemove, a shape is drawn from the initialmousedownpoint to the current mouse position. - On
mouseup, the shape is finalized, added to the shapes array, and the canvas is redrawn. - The color and size controls affect the properties of the next shape drawn.
- Clicking "Clear Canvas" removes all shapes from the array and clears the canvas.
Examples
Example 1:
Input: User selects "Circle", sets color to "red", radius to 20, and draws a circle starting at (50, 50) and ending at (100, 100).
Output: A red circle with a radius of 20 is drawn on the canvas, centered roughly around (75, 75).
Explanation: The component calculates the center of the circle based on the start and end mouse coordinates and draws it with the specified color and radius.
Example 2:
Input: User selects "Rectangle", sets color to "blue", width to 50, and height to 30, and draws a rectangle starting at (20, 30) and ending at (70, 80).
Output: A blue rectangle with a width of 50 and a height of 30 is drawn on the canvas, with its top-left corner at (20, 30).
Explanation: The component draws the rectangle using the start and end mouse coordinates as the top-left and bottom-right corners, respectively, and the specified width and height.
Example 3: (Edge Case - Rapid Drawing)
Input: User rapidly clicks and drags the mouse, drawing multiple shapes in quick succession.
Output: Each shape drawn during the rapid movement is added to the shapes array and rendered on the canvas.
Explanation: The event listeners correctly capture each `mousedown`, `mousemove`, and `mouseup` event, creating a new shape for each drawing action.
Constraints
- Canvas Size: The canvas should be 500px wide and 300px high.
- Shape Color: Shape colors should be valid CSS color strings (e.g., "red", "#FF0000", "rgb(255, 0, 0)").
- Shape Size: Radius for circles should be a positive number. Width and height for rectangles should be positive numbers.
- Performance: The rendering should be reasonably performant, even with a moderate number of shapes (e.g., up to 50). Avoid unnecessary re-renders.
- Vue Version: Use Vue 3.
Notes
- Consider using
v-forto iterate over the shapes array and draw them on the canvas. - Use
requestAnimationFramefor smoother rendering. - Think about how to handle the case where the user starts drawing outside the canvas.
- You don't need to implement undo/redo functionality.
- Focus on the core drawing and shape management logic. Advanced features like shape selection and manipulation are not required.
- The component should be self-contained and reusable.
- Error handling for invalid input (e.g., non-numeric radius) is not required, but good practice.