candle-annotator/openspec/changes/archive/2026-02-17-line-rectangle-annotations/specs/annotation-tools/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

5.7 KiB

ADDED Requirements

Requirement: Active tool includes rectangle mode

The system SHALL add "rectangle" to the available tool modes alongside "select", "break_up", "break_down", "line", "span", and "delete". Only one tool SHALL be active at a time.

Scenario: Rectangle tool in tool list

  • WHEN the Toolbox renders
  • THEN a rectangle tool button is available alongside the existing tool buttons

Requirement: Line rendering via TrendLine plugin

The system SHALL render saved line annotations using the TrendLine class (implementing ISeriesPrimitive<Time>) instead of SVG <line> elements. Each line annotation SHALL have one TrendLine primitive instance attached to the candlestick series via series.attachPrimitive(). The SvgOverlay component SHALL be removed.

Scenario: Saved lines render as canvas primitives

  • WHEN line annotations exist for the active chart
  • THEN each line renders via a TrendLine primitive on the chart canvas (not SVG overlay)

Scenario: Lines participate in autoscaling

  • WHEN a line annotation's price range extends beyond visible candle data
  • THEN the chart autoscale includes the line's price range via autoscaleInfo()

Scenario: Lines update on zoom/pan

  • WHEN user zooms or pans the chart
  • THEN line primitives automatically reposition via the ISeriesPrimitive lifecycle

Requirement: Line hit testing

The TrendLine class SHALL implement hitTest(x, y) to detect clicks near the line. Hit testing SHALL calculate the perpendicular distance from the click point to the line segment and return a hit if within 10 CSS pixels (scaled by device pixel ratio).

Scenario: Click near line detected

  • WHEN user clicks within 10 CSS pixels of a line segment
  • THEN hitTest() returns a PrimitiveHoveredItem with the annotation ID as externalId

Scenario: Click far from line not detected

  • WHEN user clicks more than 10 CSS pixels from any line segment
  • THEN hitTest() returns null

Requirement: Line selection handles via plugin

When a line is selected, the TrendLine renderer SHALL draw circular endpoint handles (radius 6px) at both endpoints of the line. The handles SHALL be rendered as part of the canvas draw call, not as separate SVG elements.

Scenario: Handles appear on selection

  • WHEN a line is selected (via click with line tool active)
  • THEN circular handles render at both endpoints of the line on the canvas

Scenario: Handles disappear on deselection

  • WHEN the selected line is deselected (Escape key or clicking elsewhere)
  • THEN the endpoint handles no longer render

MODIFIED Requirements

Requirement: Two-click line drawing

When the "line" tool is active, the system SHALL implement a two-click drawing interaction using chart.subscribeClick() for click detection and chart.subscribeCrosshairMove() for preview updates. The first click sets the start point (time, price). The second click sets the end point (time, price). After the second click, the system SHALL save an annotation with label_type: "line" and geometry containing JSON: {"startTime": <unix>, "startPrice": <float>, "endTime": <unix>, "endPrice": <float>}. The line SHALL render immediately as a TrendLine primitive attached to the candlestick series.

Scenario: Draw a trend line

  • WHEN "line" tool is active and user clicks two points on the chart
  • THEN system saves a line annotation with start/end coordinates and renders the line as a TrendLine primitive

Scenario: Visual feedback during line drawing

  • WHEN "line" tool is active and user has clicked the first point but not the second
  • THEN system displays a preview TrendLine primitive (dashed or semi-transparent) from the first point to the current crosshair position, updating via subscribeCrosshairMove()

Scenario: Cancel line drawing

  • WHEN user presses Escape during a two-click line drawing (after first click)
  • THEN system cancels the line drawing, detaches the preview primitive, and clears the drawing state without saving

Requirement: Delete annotation

When the "delete" tool is active and the user clicks on or near an existing annotation (marker, line, or rectangle), the system SHALL remove that annotation from the database and update the chart display immediately. Line and rectangle hit detection SHALL use the primitive's hitTest() method instead of SVG proximity calculation.

Scenario: Delete a marker annotation

  • WHEN "delete" tool is active and user clicks on a candle that has a marker annotation
  • THEN system removes the annotation from the database and the marker disappears from the chart

Scenario: Delete a line annotation

  • WHEN "delete" tool is active and user clicks near an existing line
  • THEN system detects the hit via TrendLine.hitTest(), sends DELETE /api/annotations/{id}, detaches the primitive from the series, and updates the annotation list

Scenario: Delete a rectangle annotation

  • WHEN "delete" tool is active and user clicks within a rectangle
  • THEN system detects the hit via RectangleDrawingPrimitive.hitTest(), sends DELETE /api/annotations/{id}, detaches the primitive, and updates the annotation list

REMOVED Requirements

Requirement: SVG overlay rendering

Reason: Replaced by TrendLine plugin rendering. Line annotations now render via ISeriesPrimitive on the chart canvas instead of SVG <line> elements in an overlay. All coordinate conversion, hit detection, and interaction handling moves to the plugin system and chart native events. Migration: Remove SvgOverlay.tsx component. Remove its usage from CandleChart.tsx. Line annotation data in the database is unchanged — the same geometry format is used by the TrendLine plugin.