candle-annotator/openspec/changes/archive/2026-02-17-line-rectangle-annotations/specs/rectangle-annotation/spec.md
Marko Djordjevic 0e8dcc6707 chore: archive line-rectangle-annotations change and sync specs
- Archived change to openspec/changes/archive/2026-02-17-line-rectangle-annotations/
- Updated annotation-tools spec: added rectangle tool mode, TrendLine plugin rendering, line hit testing, line selection handles; updated line drawing and delete requirements; removed SVG overlay rendering
- Created new rectangle-annotation spec with full requirements for rectangle drawing, rendering, hit testing, selection, deletion, and database storage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 18:16:49 +01:00

6.5 KiB

ADDED Requirements

Requirement: Rectangle tool mode

The Toolbox SHALL include a "rectangle" tool button. When activated, the chart enters rectangle drawing mode. Only one tool SHALL be active at a time — activating the rectangle tool deactivates any other active tool.

Scenario: Activate rectangle tool

  • WHEN user clicks the rectangle tool button in the Toolbox
  • THEN the rectangle tool becomes active, the button appears visually selected, and the chart cursor changes to crosshair

Scenario: Deactivate rectangle tool

  • WHEN user clicks the already-active rectangle tool button
  • THEN the tool deactivates, the mode returns to "select", and the cursor returns to default

Scenario: Rectangle tool deactivates other tools

  • WHEN the "line" tool is active and user clicks the rectangle tool button
  • THEN the line tool deactivates and the rectangle tool becomes active

Requirement: Two-click rectangle drawing

When the "rectangle" tool is active, the system SHALL implement a two-click interaction to define a rectangle. The first click sets one corner point (time, price). The second click sets the opposite corner point (time, price). The rectangle is defined by these two arbitrary data-coordinate corners — it is NOT constrained to candle boundaries.

Scenario: Draw a rectangle

  • WHEN "rectangle" tool is active and user clicks two points on the chart
  • THEN the system saves a rectangle annotation with the two corner coordinates and renders a filled semi-transparent rectangle on the chart

Scenario: First click registers corner

  • WHEN "rectangle" tool is active and user clicks on the chart
  • THEN the system records the click position as {time, price} for the first corner

Scenario: Second click completes rectangle

  • WHEN user has set the first corner and clicks a second position
  • THEN the system saves a rectangle annotation via POST /api/annotations with label_type: "rectangle" and geometry: {"startTime", "startPrice", "endTime", "endPrice"}

Requirement: Rectangle preview during drawing

After the first click, the system SHALL display a preview rectangle that stretches from the first corner to the current cursor position. The preview SHALL have a dashed border and reduced opacity to distinguish it from saved rectangles.

Scenario: Preview follows cursor

  • WHEN user has clicked the first corner and moves the mouse
  • THEN a semi-transparent preview rectangle renders from the first corner to the cursor position, updating in real-time via crosshair move events

Scenario: Preview disappears on cancel

  • WHEN user presses Escape during rectangle drawing (after first click)
  • THEN the preview rectangle disappears and the drawing is cancelled without saving

Requirement: Rectangle rendering via ISeriesPrimitive

The system SHALL render saved rectangle annotations using a RectangleDrawingPrimitive class that implements ISeriesPrimitive<Time>. Each rectangle annotation SHALL have one primitive instance attached to the candlestick series via series.attachPrimitive().

Scenario: Rectangle renders for saved annotation

  • WHEN a rectangle annotation exists for the active chart
  • THEN a semi-transparent filled rectangle renders on the chart canvas at the stored corner coordinates

Scenario: Rectangle uses annotation color

  • WHEN a rectangle annotation has a color value
  • THEN the rectangle renders with that color as fill (at reduced opacity) and border

Scenario: Rectangle updates on zoom/pan

  • WHEN user zooms or pans the chart
  • THEN rectangle primitives automatically reposition via the ISeriesPrimitive lifecycle (coordinate conversion in paneView.update())

Scenario: Rectangle z-order

  • WHEN rectangle annotations render on the chart
  • THEN they SHALL render at "bottom" z-order (behind candlesticks), consistent with span rectangles

Requirement: Rectangle hit testing

The RectangleDrawingPrimitive SHALL implement hitTest(x, y) to detect clicks within the rectangle bounds. Hit testing SHALL convert pixel coordinates to data coordinates and check if the point falls within the rectangle's time/price range.

Scenario: Click inside rectangle detected

  • WHEN user clicks at a position inside a rectangle's bounds
  • THEN hitTest() returns a PrimitiveHoveredItem with the annotation ID as externalId

Scenario: Click outside rectangle not detected

  • WHEN user clicks at a position outside all rectangle bounds
  • THEN hitTest() returns null

Requirement: Rectangle selection

The system SHALL allow users to select a rectangle annotation by clicking within its bounds when the "rectangle" or "select" tool is active.

Scenario: Click to select rectangle

  • WHEN user clicks within a rectangle annotation
  • THEN the rectangle appears selected (thicker border or increased opacity)

Scenario: Click to deselect rectangle

  • WHEN user clicks outside all rectangle annotations while one is selected
  • THEN the selection is cleared

Requirement: Rectangle deletion

The system SHALL allow users to delete rectangle annotations via the delete tool.

Scenario: Delete rectangle with delete tool

  • WHEN the "delete" tool is active and user clicks within a rectangle
  • THEN the system sends DELETE /api/annotations/{id}, removes the primitive from the chart, and updates the annotation list

Scenario: Delete selected rectangle with keyboard

  • WHEN a rectangle is selected and user presses Delete or Backspace
  • THEN the system deletes the rectangle annotation and removes it from the chart

Requirement: Rectangle database storage

Rectangle annotations SHALL be stored in the existing annotations table with label_type: "rectangle" and geometry containing JSON: {"startTime": <unix>, "startPrice": <float>, "endTime": <float>, "endPrice": <float>}. The startTime/startPrice represents one corner, endTime/endPrice the opposite corner.

Scenario: Rectangle annotation persisted

  • WHEN user completes a two-click rectangle drawing
  • THEN the system sends POST /api/annotations with label_type "rectangle", the active chart_id, selected color, and geometry JSON with the two corner coordinates

Scenario: Rectangle annotation loaded on chart switch

  • WHEN user switches to a chart that has rectangle annotations
  • THEN the system fetches annotations, creates RectangleDrawingPrimitive instances for each rectangle annotation, and attaches them to the series