Skip to main content

Add Drawing Tools to a Financial Chart

There are two ways to add drawings to a SciTrader chart, and you can use both on one chart:

  1. Point and click: enable drawing, give the user the tools, and they click the chart to place each drawing's points.
  2. In code: create a drawing's annotation with its points and add it to a pane, e.g. to show your own analysis or a saved trade.

Then you can list, select and remove drawings. Each way has TypeScript and React examples with live CodePens.

info

The SciTrader SDK has 34 drawing tools. For the full list, with each tool's id, annotation class and number of points, see Every Drawing Tool. The most popular tools have a page of their own, listed under this page in the sidebar: what the tool is for, how it works, and how to draw it on a JavaScript or React financial chart.

Enabling Point-and-Click Drawing with DrawingToolsController​

DrawingToolsController turns a chart into a drawing surface. Attach one to the chart, then start a tool with selectTool:

import { ETradingAnnotationType } from "scichart-financial-tools";
import { DrawingToolsController } from "scichart-scitrader";

// Enable drawing: adds the drawing modifiers to every pane, including panes added later
const drawing = DrawingToolsController.attach(financeChartPanel.financeApi);

// Start a tool: the user clicks the chart to place its points
drawing.selectTool(ETradingAnnotationType.FibonacciRetracementAnnotation);

drawing.stop(); // cancel the active tool, discarding a drawing in progress
drawing.detach(); // turn drawing off; the drawings stay on the chart

The controller has no UI of its own, so any button, menu or keyboard shortcut can call selectTool. For a ready-made one, use the Drawing Toolbar. The controller:

  • adds the drawing modifiers to every pane, including panes added later, e.g. when a study adds one;
  • suspends pan, x-axis drag and zoom-to-extents while a tool is active, so a drag draws instead of panning, and resumes them when it finishes;
  • shows the quick-edit toolbar on a selected drawing (see Editing Drawings);
  • registers the drawing types (registerDrawingTools()), so drawings are saved with the chart.

When a tool finishes. A click-to-place tool finishes when its last point is placed, and a freehand tool when the stroke ends; activeTool then returns to null. The eraser stays on until stop() or another tool is selected, and removes only user drawings, never a study's annotations.

Touch screens need the touch option; see Keyboard and Touch.

In React, useDrawingTools(chart) from scichart-scitrader-react attaches a controller once the chart is ready, and detaches it on unmount. It returns the controller, and the activeTool and drawings as React state:

import { DrawingToolbar, SciFinanceChartView, useDrawingTools } from "scichart-scitrader-react";

const [chartApi, setChartApi] = React.useState<ISciFinanceChartPanelApi>();
const { controller, activeTool, drawings } = useDrawingTools(chartApi);

<DrawingToolbar controller={controller} />
<SciFinanceChartView config={config} onInit={setChartApi} />

DrawingToolsController Events​

EventPayload
activeToolChanged
Raised when a tool is selected, finishes, or is stopped
The active tool's id, or null
drawingsChanged
Raised when a drawing is added or removed, by the user, your code or the eraser
Every drawing, as IDrawingItem[]
drawing.activeToolChanged.subscribe((tool) => console.log("active tool:", tool)); // null once placed
drawing.drawingsChanged.subscribe((items) => console.log(items.length, "drawings"));

Other events come from elsewhere:

  • A drawing is selected, deselected, moved or clicked: its annotation's own events, selectedChanged, dragEnded, clicked and more. See Selection and Edit Events.
  • A row of the drawing list is clicked, edited or deleted: the list's onSelect, onEdit, onDelete and onClearAll. See Drawing List Callbacks.
  • A key selects a drawing, or asks to draw: the keyboard modifier's onSelectionChanged, onAddAnnotation and onCancelPlacement. See Keyboard and Touch.

TypeScript Example: Point-and-Click Drawing with DrawingToolsController​

A BTC-USD chart from Coinbase with the drawing-tools rail on the left. Pick a tool, then click the chart to place its points; the line above follows activeToolChanged and drawingsChanged. The rail's last button opens every tool.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import {
CandleInterval,
CoinbaseExchange,
defaultExchangeProvider,
DRAWING_TOOL_BY_ID,
DrawingToolbar,
DrawingToolsController,
idbPriceStore,
OHLCStudy,
SciFinanceChartPanel,
VolumeStudy,
} from "scichart-scitrader";

// This example expects this HTML:
// <div style="display: flex; flex-direction: column; height: 100%">
// <div id="status"></div>
// <div style="display: flex; flex: 1; min-height: 0">
// <div id="tools"></div>
// <div id="chart" style="flex: 1; min-width: 0"></div>
// </div>
// </div>

// Register a data source, once, at app startup
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);

async function createChart() {
const status = document.getElementById("status");
Object.assign(status.style, statusStyle);

const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol: "BTC-USD",
interval: CandleInterval.SIX_HOURS,
period: "3M",
studies: [new OHLCStudy(), new VolumeStudy()],
});

// 1. Enable point-and-click drawing: the controller adds the drawing modifiers to every pane,
// including panes added later, and shows a quick-edit toolbar on a selected drawing.
// It has no UI of its own: a toolbar, menu or shortcut calls selectTool
const drawing = DrawingToolsController.attach(financeChartPanel.financeApi);

// 2. A toolbar: the SDK's drawing-tools rail. Click a tool, then click the chart to place its
// points. Click the tool again to cancel. The last button opens every tool, grouped
const toolbar = DrawingToolbar.create(document.getElementById("tools"), drawing, { orientation: "vertical" });

// 3. Follow what the user does.
// activeToolChanged: a tool was started, finished or stopped (null when none is active)
// drawingsChanged: a drawing was added or removed, with the full list
const show = () => {
const tool = drawing.activeTool ? DRAWING_TOOL_BY_ID.get(drawing.activeTool)?.label : "none";
status.textContent = `Active tool: ${tool}. Drawings on the chart: ${drawing.drawings.length}`;
};
drawing.activeToolChanged.subscribe(show);
drawing.drawingsChanged.subscribe(show);
show();

// When the page goes away: toolbar.destroy(); drawing.detach(); financeChartPanel.cleanup();
return { financeChartPanel, drawing, toolbar };
}

// The status line uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const statusStyle: Partial<CSSStyleDeclaration> = {
padding: "8px 12px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: "13px",
};

createChart();

React Example: Point-and-Click Drawing with useDrawingTools​

The same chart in React. useDrawingTools attaches the controller and returns the active tool and drawings as state, and the React DrawingToolbar is the same rail.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import * as React from "react";
import {
CandleInterval,
CoinbaseExchange,
defaultExchangeProvider,
DRAWING_TOOL_BY_ID,
idbPriceStore,
ISciFinanceChartPanelApi,
ISciFinanceChartPanelConfig,
OHLCStudy,
VolumeStudy,
} from "scichart-scitrader";
import { DrawingToolbar, SciFinanceChartView, useDrawingTools } from "scichart-scitrader-react";

// Register a data source, once, at app startup
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);

export function PointAndClickDrawingChart() {
const [chartApi, setChartApi] = React.useState<ISciFinanceChartPanelApi>();

// 1. Enable point-and-click drawing: useDrawingTools attaches a DrawingToolsController once the
// chart is ready, and detaches it on unmount. It also returns the active tool and the drawings
// as React state, kept up to date from the controller's activeToolChanged and drawingsChanged
const { controller, activeTool, drawings } = useDrawingTools(chartApi);

// Create the config once per mounted chart: studies are live objects bound to one chart
const config = React.useMemo<ISciFinanceChartPanelConfig>(
() => ({
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol: "BTC-USD",
interval: CandleInterval.SIX_HOURS,
period: "3M",
studies: [new OHLCStudy(), new VolumeStudy()],
}),
[]
);

const tool = activeTool ? DRAWING_TOOL_BY_ID.get(activeTool)?.label : "none";

// Fills its parent, so give the parent a height
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={statusStyle}>{`Active tool: ${tool}. Drawings on the chart: ${drawings.length}`}</div>
<div style={{ display: "flex", flex: 1, minHeight: 0 }}>
{/* 2. A toolbar: the SDK's drawing-tools rail. Click a tool, then click the chart to
place its points. It renders once the controller exists */}
<DrawingToolbar controller={controller} orientation="vertical" />
<div style={{ flex: 1, minWidth: 0 }}>
<SciFinanceChartView config={config} onInit={setChartApi} />
</div>
</div>
</div>
);
}

// The status line uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const statusStyle: React.CSSProperties = {
padding: "8px 12px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
color: "var(--st-ui-text-muted, #9da2bc)",
fontSize: 13,
};

Adding Drawings Programmatically​

A drawing is an annotation from scichart-financial-tools. To add one in code:

  1. Register the drawing types, once at startup, with registerDrawingTools(), so the chart treats your annotations as user drawings: listed, saved and themed. DrawingToolsController.attach also does this.
  2. Create the annotation with its points, in data coordinates: x is a candle's time in seconds (Unix time), and y is a price. The catalogue lists each tool's class and how many points it takes.
  3. Add it to a pane's surface: chart.chartPanes.get(PaneId.DEFAULT) is the price pane. A study's pane is chart.chartPanes.get(study.chartPaneId).
warning

A point's x is a candle's time in seconds, not milliseconds as JavaScript dates use: divide Date.getTime() by 1000. A time in milliseconds places the drawing far off to the right of the chart.

import { Point } from "scichart";
import { FibonacciRetracementAnnotation } from "scichart-financial-tools";
import { PaneId, registerDrawingTools } from "scichart-scitrader";

registerDrawingTools(); // once, at startup

const chart = financeChartPanel.financeApi;
const pricePane = chart.chartPanes.get(PaneId.DEFAULT).surface;

pricePane.annotations.add(
new FibonacciRetracementAnnotation({
points: [new Point(1767225600, 75600), new Point(1768435200, 84850)], // (time in seconds, price)
isEditable: true, // the user can select, drag and edit it
})
);

Where to put a drawing. To place drawings on the chart's own data, read the loaded candles from chart.dataManager: xValues are the candles' times, and getValues(getSourceIdByName(DEFAULT_FEED_ID, EDataSourceStringId.HIGH)) their highs, likewise LOW, OPEN and CLOSE. The examples below find the high and low of the last 90 candles this way.

Changing a drawing later. Keep the annotation, or find it in drawing.drawings, and set its properties: annotation.points = [...] moves it, and its own options, such as stroke or a Fibonacci's thresholds, restyle it. See Editing Drawings.

note

Patterns (Elliott waves and XABCD) are poly lines with a label at each point. The SDK's own pattern helpers aren't exported, so build the labels yourself; see Elliott Wave. The label text is what identifies the pattern, e.g. in the drawing list.

TypeScript Example: Adding Drawings in Code​

A BTC-USD chart from Coinbase with three drawings added in code: a Fibonacci retracement of the last 90 candles' move, a trend line through two lows, and a horizontal line at the latest close. The list on the right follows the controller. The buttons add the drawings again, remove the Fibonacci retracements by type, or remove everything.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import { Point } from "scichart";
import {
ETradingAnnotationType,
ExtendedLineAnnotation,
FibonacciRetracementAnnotation,
HorizontalTrendLineAnnotation,
} from "scichart-financial-tools";
import {
CandleInterval,
CoinbaseExchange,
DEFAULT_FEED_ID,
defaultExchangeProvider,
DrawingList,
DrawingToolsController,
EDataSourceStringId,
idbPriceStore,
OHLCStudy,
PaneId,
registerDrawingTools,
SciFinanceChart,
SciFinanceChartPanel,
VolumeStudy,
} from "scichart-scitrader";

// This example expects this HTML:
// <div style="display: flex; flex-direction: column; height: 100%">
// <div id="toolbar"></div>
// <div style="display: flex; flex: 1; min-height: 0">
// <div id="chart" style="flex: 1; min-width: 0"></div>
// <div id="drawings" style="width: 280px; overflow-y: auto"></div>
// </div>
// </div>

// Once, at app startup: register a data source, and the drawing tools' annotation types.
// registerDrawingTools() makes drawings added in code count as user drawings: listed, saved with the
// chart, and restyled by its theme. Without it they still draw, but as plain annotations
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);
registerDrawingTools();

async function createChart() {
const toolbar = document.getElementById("toolbar");
Object.assign(toolbar.style, toolbarStyle);

const financeChartPanel = await SciFinanceChartPanel.create(document.getElementById("chart"), {
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol: "BTC-USD",
interval: CandleInterval.SIX_HOURS,
period: "3M",
studies: [new OHLCStudy(), new VolumeStudy()],
});
const chart = financeChartPanel.financeApi;

// The controller isn't needed to add drawings in code. Here it lists them (drawings,
// drawingsChanged), removes them, and lets the user select and edit them
const drawing = DrawingToolsController.attach(chart);

// Add drawings in code: create each annotation with its points in data coordinates
// (x: a candle's time in seconds, y: a price), and add it to a pane's surface
const addDrawings = () => {
const candles = getCandles(chart);
const n = candles.times.length;
const pricePane = chart.chartPanes.get(PaneId.DEFAULT).surface;
const low = lowest(candles, n - 90, n);
const high = highest(candles, n - 90, n);
pricePane.annotations.add(
// A Fibonacci retracement of the last 90 candles' move, from the low to the high in time order
new FibonacciRetracementAnnotation({ points: low.x < high.x ? [low, high] : [high, low], isEditable: true }),
// A trend line through two lows, extended to the right
new ExtendedLineAnnotation({
points: [lowest(candles, n - 90, n - 45), lowest(candles, n - 45, n)],
extendEnd: true,
stroke: "#26a69a",
strokeThickness: 2,
isEditable: true,
}),
// A horizontal line at the latest close
new HorizontalTrendLineAnnotation({
points: [new Point(candles.times[n - 1], candles.closes[n - 1])],
stroke: "#ff9f1c",
isEditable: true,
})
);
};
addDrawings();

// The drawing list follows the controller: a row per drawing, with select and delete
const list = DrawingList.create(document.getElementById("drawings"), { controller: drawing, title: "Drawings" });

toolbar.append(
button("Add the drawings again", addDrawings),
// drawing.drawings lists the user's drawings, oldest first. Each has a type, a toolId and its annotation
button("Remove the Fibonacci retracements", () =>
drawing.drawings
.filter((d) => d.type === ETradingAnnotationType.FibonacciRetracementAnnotation)
.forEach((d) => drawing.remove(d))
),
button("Remove all", () => drawing.remove()) // remove() with no drawing removes every one
);

// When the page goes away: list.destroy(); drawing.detach(); financeChartPanel.cleanup();
return { financeChartPanel, drawing, list };
}
// ---------------------------------------------------------------------------------------------
// Not part of the SDK: helpers that read the loaded candles, to choose where to place drawings
// ---------------------------------------------------------------------------------------------

// The loaded candles: times in seconds (the x values of a SciTrader chart), and prices
function getCandles(chart: SciFinanceChart) {
const dm = chart.dataManager;
const values = (name: EDataSourceStringId) => dm.getValues<number>(dm.getSourceIdByName(DEFAULT_FEED_ID, name));
return {
times: dm.xValues,
highs: values(EDataSourceStringId.HIGH),
lows: values(EDataSourceStringId.LOW),
closes: values(EDataSourceStringId.CLOSE),
};
}
type TCandles = ReturnType<typeof getCandles>;

// The lowest low, or highest high, of candles [from, to), as a point on the chart
function lowest(c: TCandles, from: number, to: number): Point {
let i = from;
for (let j = from; j < to; j++) if (c.lows[j] < c.lows[i]) i = j;
return new Point(c.times[i], c.lows[i]);
}
function highest(c: TCandles, from: number, to: number): Point {
let i = from;
for (let j = from; j < to; j++) if (c.highs[j] > c.highs[i]) i = j;
return new Point(c.times[i], c.highs[i]);
}

function button(text: string, onClick: () => void) {
const b = document.createElement("button");
b.textContent = text;
b.onclick = onClick;
Object.assign(b.style, buttonStyle);
return b;
}
// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: Partial<CSSStyleDeclaration> = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: "8px",
padding: "8px",
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
};
const buttonStyle: Partial<CSSStyleDeclaration> = {
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: "6px",
background: "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: "13px",
cursor: "pointer",
};

createChart();

React Example: Adding Drawings in Code​

The same chart in React. The drawings are added in onInit, once the chart has loaded its candles.

The code for this example is found below.

import "scichart-scitrader/scitrader.css";
import * as React from "react";
import { Point } from "scichart";
import {
ETradingAnnotationType,
ExtendedLineAnnotation,
FibonacciRetracementAnnotation,
HorizontalTrendLineAnnotation,
} from "scichart-financial-tools";
import {
CandleInterval,
CoinbaseExchange,
DEFAULT_FEED_ID,
defaultExchangeProvider,
EDataSourceStringId,
idbPriceStore,
ISciFinanceChartPanelApi,
ISciFinanceChartPanelConfig,
OHLCStudy,
PaneId,
registerDrawingTools,
SciFinanceChart,
VolumeStudy,
} from "scichart-scitrader";
import { DrawingList, SciFinanceChartView, useDrawingTools } from "scichart-scitrader-react";

// Once, at app startup: register a data source, and the drawing tools' annotation types.
// registerDrawingTools() makes drawings added in code count as user drawings: listed, saved with the
// chart, and restyled by its theme. Without it they still draw, but as plain annotations
defaultExchangeProvider.registerExchange(CoinbaseExchange, idbPriceStore);
registerDrawingTools();

// Add drawings in code: create each annotation with its points in data coordinates
// (x: a candle's time in seconds, y: a price), and add it to a pane's surface
function addDrawings(chart: SciFinanceChart) {
const candles = getCandles(chart);
const n = candles.times.length;
const pricePane = chart.chartPanes.get(PaneId.DEFAULT).surface;
const low = lowest(candles, n - 90, n);
const high = highest(candles, n - 90, n);
pricePane.annotations.add(
// A Fibonacci retracement of the last 90 candles' move, from the low to the high in time order
new FibonacciRetracementAnnotation({ points: low.x < high.x ? [low, high] : [high, low], isEditable: true }),
// A trend line through two lows, extended to the right
new ExtendedLineAnnotation({
points: [lowest(candles, n - 90, n - 45), lowest(candles, n - 45, n)],
extendEnd: true,
stroke: "#26a69a",
strokeThickness: 2,
isEditable: true,
}),
// A horizontal line at the latest close
new HorizontalTrendLineAnnotation({
points: [new Point(candles.times[n - 1], candles.closes[n - 1])],
stroke: "#ff9f1c",
isEditable: true,
})
);
}

export function ProgrammaticDrawingChart() {
const [chartApi, setChartApi] = React.useState<ISciFinanceChartPanelApi>();
// The controller isn't needed to add drawings in code. Here it lists them (drawings, as React
// state), removes them, and lets the user select and edit them
const { controller, drawings } = useDrawingTools(chartApi);

// Create the config once per mounted chart: studies are live objects bound to one chart
const config = React.useMemo<ISciFinanceChartPanelConfig>(
() => ({
exchangeName: CoinbaseExchange.name, // name="Coinbase" matches the built-in CoinbaseExchange
symbol: "BTC-USD",
interval: CandleInterval.SIX_HOURS,
period: "3M",
studies: [new OHLCStudy(), new VolumeStudy()],
}),
[]
);

// Add the drawings once the chart has loaded its candles
const onInit = (api: ISciFinanceChartPanelApi) => {
addDrawings(api.financeApi);
setChartApi(api);
};

// Fills its parent, so give the parent a height
return (
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={toolbarStyle}>
<button style={buttonStyle} disabled={!chartApi} onClick={() => addDrawings(chartApi.financeApi)}>
Add the drawings again
</button>
{/* drawings lists the user's drawings, oldest first. Each has a type, a toolId and its annotation */}
<button
style={buttonStyle}
disabled={!controller}
onClick={() =>
drawings
.filter((d) => d.type === ETradingAnnotationType.FibonacciRetracementAnnotation)
.forEach((d) => controller.remove(d))
}
>
Remove the Fibonacci retracements
</button>
{/* remove() with no drawing removes every one */}
<button style={buttonStyle} disabled={!controller} onClick={() => controller.remove()}>
Remove all
</button>
</div>
<div style={{ display: "flex", flex: 1, minHeight: 0 }}>
<div style={{ flex: 1, minWidth: 0 }}>
<SciFinanceChartView config={config} onInit={onInit} />
</div>
{/* The drawing list follows the controller: a row per drawing, with select and delete */}
<DrawingList controller={controller} title="Drawings" style={{ width: 280, overflowY: "auto" }} />
</div>
</div>
);
}
// ---------------------------------------------------------------------------------------------
// Not part of the SDK: helpers that read the loaded candles, to choose where to place drawings
// ---------------------------------------------------------------------------------------------

// The loaded candles: times in seconds (the x values of a SciTrader chart), and prices
function getCandles(chart: SciFinanceChart) {
const dm = chart.dataManager;
const values = (name: EDataSourceStringId) => dm.getValues<number>(dm.getSourceIdByName(DEFAULT_FEED_ID, name));
return {
times: dm.xValues,
highs: values(EDataSourceStringId.HIGH),
lows: values(EDataSourceStringId.LOW),
closes: values(EDataSourceStringId.CLOSE),
};
}
type TCandles = ReturnType<typeof getCandles>;

// The lowest low, or highest high, of candles [from, to), as a point on the chart
function lowest(c: TCandles, from: number, to: number): Point {
let i = from;
for (let j = from; j < to; j++) if (c.lows[j] < c.lows[i]) i = j;
return new Point(c.times[i], c.lows[i]);
}
function highest(c: TCandles, from: number, to: number): Point {
let i = from;
for (let j = from; j < to; j++) if (c.highs[j] > c.highs[i]) i = j;
return new Point(c.times[i], c.highs[i]);
}

// The toolbar uses SciTrader's UI colours: its --st-ui-* CSS variables, with the stylesheet's defaults
const toolbarStyle: React.CSSProperties = {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
gap: 8,
padding: 8,
background: "var(--st-ui-background, #2b2839)",
borderBottom: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
};
const buttonStyle: React.CSSProperties = {
padding: "4px 10px",
border: "1px solid var(--st-ui-divider, rgba(255,255,255,0.1))",
borderRadius: 6,
background: "var(--st-ui-surface, #373447)",
color: "var(--st-ui-text, #ffffff)",
font: "inherit",
fontSize: 13,
cursor: "pointer",
};

Listing, Selecting and Removing Drawings​

The controller keeps the list of the user's drawings, whether drawn with point and click, added in code, or restored from a saved chart:

MemberWhat it does
drawingsThe drawings, oldest first, as IDrawingItem: its annotation, its type, and the toolId that made it
select(item)Selects a drawing, as a click on it would
clearSelection()Deselects every drawing
remove(item)Removes one drawing; remove() with no drawing removes every one
openEditor(item)Selects a drawing and opens the full editor for it; see Editing Drawings
// Remove every Fibonacci retracement
drawing.drawings
.filter((item) => item.type === ETradingAnnotationType.FibonacciRetracementAnnotation)
.forEach((item) => drawing.remove(item));

The Drawing List shows the drawings to the user, with buttons to select, edit and delete them.

Saving and Restoring Drawings​

Drawings are saved with the chart: financeChartPanel.toJSON() includes every drawing on every pane, under finance.annotations, and SciFinanceChartPanel.fromJSON() restores them. Call registerDrawingTools() before restoring without a controller, and SciFinanceChart.registerDrawingType(name) for annotation types of your own. See Save and Restore.

DrawingToolsController API​

MemberWhat it does
DrawingToolsController.attach(chart, options)Enables drawing on a chart, financeChartPanel.financeApi
selectTool(id)Starts a tool
stop()Stops the active tool, discarding a drawing in progress
activeToolThe active tool's id, or null
lastUsedToolThe last tool selected, for a "draw again" shortcut
drawings, select, clearSelection, remove, openEditorSee Listing, Selecting and Removing Drawings
activeToolChanged, drawingsChangedSee DrawingToolsController Events
detach()Turns drawing off. The drawings stay on the chart
Option (IDrawingToolsControllerOptions)What it does
editorContainer, editorRootClassName, editorPanelClassName, onOpenFullEditorWhere and how the full editor opens; see Editing Drawings
touch, selectFinishedDrawing, resumeGesturesTouch layouts; see Keyboard and Touch
The DrawingToolsController class, with its TSDoc
/**
* Drawing tools for a chart, independent of any UI framework: attach one to a
* {@link SciFinanceChart}, then call {@link selectTool} from whatever toolbar you build. The SDK's
* vanilla `DrawingToolbar` and the React `DrawingToolbar` both drive one of these.
*
* It adds the drawing modifiers to every pane, including panes added later: placement,
* freehand, eraser, and the floating quick-edit toolbar shown when a drawing is selected. It
* suspends pan, x-axis drag and zoom-to-extents while a tool is active, so a drag draws instead
* of panning. And it returns to "no tool" when a drawing is finished. Placed drawings are saved
* with the chart (`toJSON`), because the tools' annotation types are registered as user drawings.
*
* For a touch layout, see the `touch`, `selectFinishedDrawing` and `resumeGestures` options.
*
* ```ts
* const drawing = DrawingToolsController.attach(panel.financeApi);
* drawing.selectTool(ETradingAnnotationType.FibonacciRetracementAnnotation);
* drawing.activeToolChanged.subscribe((tool) => …); // null once the drawing is placed
* ```
*/
class DrawingToolsController {
/** Raised when a tool is selected, finished or stopped, with the active tool or `null`. */
readonly activeToolChanged: EventHandler<TDrawingToolId>;
/** Raised when drawings are added or removed, with the full list. */
readonly drawingsChanged: EventHandler<readonly IDrawingItem[]>;
/** Attach drawing tools to a chart. Call {@link detach} before deleting the chart, or leave it to the chart's teardown. */
static attach(chart: SciFinanceChart, options?: IDrawingToolsControllerOptions): DrawingToolsController;
/** The tool being used, or `null`. */
get activeTool(): TDrawingToolId | null;
/** The last tool selected: for a "draw again" shortcut. */
get lastUsedTool(): TDrawingToolId | null;
/** The user's drawings on the chart, oldest first. */
get drawings(): readonly IDrawingItem[];
/**
* Start a tool. Click-to-place tools finish when their last point is placed, freehand tools
* when the stroke ends; either way {@link activeTool} returns to `null`. The eraser stays on
* until {@link stop} or another tool is selected, and removes only user drawings.
*/
selectTool(id: TDrawingToolId): void;
/** Stop the active tool, discarding a drawing in progress. */
stop(): void;
/** Remove one drawing, or all of them. */
remove(item?: IDrawingItem): void;
/** Select a drawing, as a click on it would. */
select(item: IDrawingItem): void;
/**
* Select a drawing and open the full editor for it, as the quick-edit toolbar's "more" button
* does. Calls {@link IDrawingToolsControllerOptions.onOpenFullEditor}. Needs an `editorContainer`.
*/
openEditor(item: IDrawingItem): void;
/** Deselect every drawing, closing the quick-edit toolbar and the full editor. */
clearSelection(): void;
/** Remove the modifiers from every pane. The drawings stay on the chart. */
detach(): void;
}
The IDrawingToolsControllerOptions and IDrawingItem interfaces, with their TSDoc
interface IDrawingToolsControllerOptions {
/**
* Where the full annotation editor (every option of the selected drawing) is mounted when
* the user opens it from the floating quick-edit toolbar. Omit to offer the quick-edit
* toolbar only.
*/
editorContainer?: HTMLElement;
/**
* Called when the full editor opens, from the quick-edit toolbar or {@link DrawingToolsController.openEditor},
* e.g. to show the panel that holds it.
*/
onOpenFullEditor?: (annotation: IAnnotation) => void;
/** Class added to the full editor's root element in {@link editorContainer}. */
editorRootClassName?: string;
/** Class added to the full editor's panel. */
editorPanelClassName?: string;
/**
* For a touch layout: a long press on a drawing selects it, as a click does with a mouse, and
* placement uses a movable cursor: drag to aim, tap to commit each point. The cursor applies
* to a mouse too, so turn this on for touch devices only, e.g. from `(pointer: coarse)`.
* `true` uses the default selection timings; pass options to change them.
*/
touch?: boolean | IAnnotationTouchSelectionModifierOptions;
/**
* Whether a drawing stays selected, showing the quick-edit toolbar, once it is placed.
* Default `true`. Turn it off where an open editor would cover the chart, as on a phone.
*/
selectFinishedDrawing?: boolean;
/**
* Restores chart gestures when a tool finishes or is stopped. The controller suspends pan,
* x-axis drag and zoom-to-extents while a tool is active, so a drag draws instead of panning.
* By default it turns them back on. Pass this if your app sometimes keeps them off, such as a
* touch "cursor mode" where a drag moves the crosshair instead.
*/
resumeGestures?: () => void;
}

/** One user drawing on the chart, as listed by {@link DrawingToolsController.drawings}. */
interface IDrawingItem {
/** The annotation's `id`. */
id: string;
/** The annotation type, an `ETradingAnnotationType` value. */
type: string;
/** The tool that makes this kind of drawing (tells a pattern from a plain polyline). */
toolId?: TDrawingToolId;
/** The annotation itself, for selecting or deleting it. */
annotation: IAnnotation;
}
The React useDrawingTools hook, from scichart-scitrader-react, with its TSDoc
interface IUseDrawingToolsResult {
/** Available once the chart has initialised. */
controller: DrawingToolsController | undefined;
activeTool: TDrawingToolId | null;
drawings: readonly IDrawingItem[];
}
/**
* Drawing tools for a React chart: attaches a {@link DrawingToolsController} to the chart once it
* is ready, detaches it on unmount, and returns the active tool and drawings as state.
*
* ```tsx
* const [chart, setChart] = React.useState<ISciFinanceChartViewApi>();
* const { controller, activeTool, drawings } = useDrawingTools(chart);
*
* <DrawingToolbar controller={controller} />
* <SciFinanceChartView config={config} onInit={setChart} />
* ```
*/
function useDrawingTools(chart: ISciFinanceChartPanelApi | undefined, options?: IDrawingToolsControllerOptions): IUseDrawingToolsResult;