Hone logo
Hone
Problems

React Annotation Tool Challenge

This challenge asks you to build a foundational annotation tool using React and TypeScript. Annotation tools are crucial for various applications, from image editing and data labeling to code review and content moderation. Successfully completing this challenge will demonstrate your ability to manage UI state, handle user interactions, and structure a reusable React component.

Problem Description

Your task is to create a React component that allows users to draw rectangular annotations on an image. The component should enable users to:

  1. Display an Image: Render a provided image within a designated area.
  2. Draw Rectangles: Allow users to click and drag on the image to draw rectangular annotations.
  3. Visualize Annotations: Display the drawn rectangles on top of the image.
  4. Manage Annotations: Maintain a list of all created annotations, including their position and dimensions.
  5. Basic Interaction: Users should be able to start drawing a new annotation by clicking and dragging, and the annotation should be finalized upon releasing the mouse button.

Key Requirements:

  • The component must be built using React and TypeScript.
  • Annotations should be represented as rectangles defined by their x, y (top-left corner), width, and height.
  • The drawing process should be intuitive: click and drag to define the rectangle's boundaries.
  • Annotations should be visually distinct (e.g., a colored border).
  • The component should accept the image source URL as a prop.
  • The component should expose a way to access the list of annotations (e.g., via a callback prop).

Expected Behavior:

  • When the user clicks and starts dragging, a temporary rectangle might be shown to indicate the drawing in progress.
  • Upon releasing the mouse, a permanent annotation should be added to the list and rendered on the image.
  • The tool should be responsive to the image's dimensions, and annotations should maintain their relative positions.

Edge Cases:

  • Drawing zero-width or zero-height rectangles (consider whether to allow or ignore these).
  • Rapidly clicking and releasing without dragging (should not create an annotation).
  • Drawing outside the image boundaries (annotations should ideally be clipped or the drawing confined to the image).

Examples

Example 1: Basic Drawing

Input:

  • imageUrl: "path/to/your/image.jpg"
  • User clicks at (x: 50, y: 100) and drags to (x: 150, y: 200) before releasing.

Output:

  • The image is displayed.
  • A rectangle is rendered on the image with its top-left corner at (50, 100), width 100, and height 100.
  • An annotation object like { id: "unique-id-1", x: 50, y: 100, width: 100, height: 100 } is added to the internal state.
  • A callback onAnnotationsChange is called with the updated list of annotations.

Example 2: Multiple Annotations

Input:

  • imageUrl: "path/to/another/image.png"
  • User draws the first annotation from (x: 20, y: 30) to (x: 80, y: 70).
  • User then draws a second annotation from (x: 100, y: 120) to (x: 130, y: 180).

Output:

  • The image is displayed.
  • Two rectangles are rendered on the image.
  • The internal state contains two annotation objects.
  • onAnnotationsChange is called with an array containing both annotations.

Example 3: Edge Case - Minimal Drag

Input:

  • imageUrl: "path/to/sample.gif"
  • User clicks at (x: 75, y: 75) and immediately releases without significant dragging.

Output:

  • The image is displayed.
  • No new annotation is added to the list.
  • onAnnotationsChange is called with the same list of annotations as before the click.

Constraints

  • The annotation tool should be a functional React component.
  • The image dimensions should not exceed 1000px in width or 1000px in height for testing purposes.
  • The number of annotations should not exceed 50 per image.
  • The component should efficiently re-render only when necessary.

Notes

  • Consider using CSS for styling the annotations. Absolute positioning will be key for placing them correctly on the image.
  • You'll need to manage several pieces of state: the list of current annotations, the coordinates of the rectangle being drawn (if any), and whether the user is currently drawing.
  • Think about how to handle mouse events (onMouseDown, onMouseMove, onMouseUp) to capture the drawing interaction.
  • For simplicity, you don't need to implement editing, deletion, or resizing of annotations in this challenge. Focus on the core drawing functionality.
  • When calculating width and height from two points, remember that the user might drag from right-to-left or bottom-to-top. Your logic should account for this to ensure width and height are always positive values.
  • You can use a simple unique ID generator (e.g., a counter or Date.now()) for annotation IDs.
Loading editor...
typescript