Skip to content

Drawing Tools

Drawing tools let users annotate the chart with lines and markers. They receive pointer events from the overlay canvas and render on every redraw.

Built-in Tools

FibonacciRetracement

Click two points on the chart to draw Fibonacci retracement levels (0%, 23.6%, 38.2%, 50%, 61.8%, 78.6%, 100%). Double-click to cancel a pending draw.

ts
import { FibonacciRetracement } from 'chartgpu';

const fib = new FibonacciRetracement();
chart.addTool(fib);

fib.active = true;
chart.activateTool(fib);

Levels are color-coded and labeled on the left edge. Each shape stores the anchor prices — viewport panning/zooming re-renders correctly.

Rectangle

Drag to draw a shaded rectangular region over a price/time area.

ts
import { Rectangle } from 'chartgpu';

const rect = new Rectangle();
chart.addTool(rect);

rect.active = true;
chart.activateTool(rect);

Clicking and dragging defines the bounding box. Multiple rectangles can be drawn while the tool is active.

ParallelChannel

Three-click tool: click once for the base line start, once for the end, then click a third point to set the channel offset. Double-click to cancel a pending channel.

ts
import { ParallelChannel } from 'chartgpu';

const channel = new ParallelChannel();
chart.addTool(channel);

channel.active = true;
chart.activateTool(channel);

Draws a base line, a parallel offset line, and a dashed midline with a subtle fill between them.

TrendLine

Click two points on the candle panel to draw a line. Double-click to cancel a pending line.

ts
import { TrendLine } from 'chartgpu';

const trendLine = new TrendLine();
chart.addTool(trendLine);

// Activate
trendLine.active = true;
chart.activateTool(trendLine);

// Deactivate
trendLine.active = false;
chart.activateTool(null);

// Clear all lines
trendLine.clear();
PropertyDescription
activeWhether the tool accepts pointer input.
cursorReturns 'crosshair' when active, 'default' otherwise.

HorizontalRay

Double-click on the candle panel to place a horizontal price level. Double-click again near an existing level to remove it.

ts
import { HorizontalRay } from 'chartgpu';

const hRay = new HorizontalRay();
chart.addTool(hRay);

// Access placed levels
console.log(hRay.levels);  // number[]

Unlike TrendLine, HorizontalRay doesn't need to be explicitly activated — it responds to double-click at all times.

Custom Drawing Tools

Extend DrawingTool:

ts
import { DrawingTool, type DrawState } from 'chartgpu';

class MyAnnotationTool extends DrawingTool {
  private labels: { x: number; y: number; text: string }[] = [];
  active = false;

  get cursor() { return this.active ? 'text' : 'default'; }

  onPointerDown(e: PointerEvent, state: DrawState): boolean {
    if (!this.active) return false;
    const { section } = state;
    const relY = e.offsetY - section.top;
    if (relY < 0 || relY > section.height) return false;
    this.labels.push({ x: e.offsetX, y: e.offsetY, text: 'Note' });
    return true;
  }

  onPointerMove(_e: PointerEvent, _state: DrawState): boolean { return false; }
  onPointerUp(_e: PointerEvent, _state: DrawState): boolean   { return false; }
  onDblClick(_e: MouseEvent, _state: DrawState): boolean      { return false; }

  clear(): void { this.labels = []; }

  draw(state: DrawState): void {
    const { ctx } = state;
    ctx.save();
    ctx.font = '12px monospace';
    ctx.fillStyle = '#f59e0b';
    for (const { x, y, text } of this.labels) ctx.fillText(text, x, y);
    ctx.restore();
  }
}

Returning true from handlers

If a handler returns true, the event is consumed — the chart won't pan or zoom in response. Return false to let the chart handle it normally.

Released under the MIT License.