Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.tsx

tradingAnnotationExampleUtils.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    AnnotationHoverModifier,
3    ECursorStyle,
4    EObservableArrayChangedAction,
5    EXyDirection,
6    MouseWheelZoomModifier,
7    NumberRange,
8    ZoomExtentsModifier,
9} from "scichart";
10import {
11    EAnnotationVisibilityMode,
12    ESnapMode,
13    FreehandDrawingAnnotation,
14    FreehandDrawingModifier,
15    IFreehandDrawingAnnotationOptions,
16} from "scichart-financial-tools";
17import { createFinancialChart, TRADING_ANNOTATION_COLORS } from "../_shared/tradingAnnotationExampleUtils";
18
19export type TFreehandVariant = "editableOutline" | "nonEditableLine" | "thickHighlight" | "locked";
20
21const generateHandDrawnTrendline = () => {
22    const startX = 1705104000; // 2024-01-13 00:00 UTC
23    const endX = 1705276800; // 2024-01-15 00:00 UTC
24    const startY = 65000;
25    const endY = 67500;
26    const count = 110;
27    let seed = 1337;
28    const rand = () => {
29        seed = (seed * 9301 + 49297) % 233280;
30        return seed / 233280;
31    };
32    const points: { x: number; y: number }[] = [];
33    for (let i = 0; i < count; i++) {
34        const t = i / (count - 1);
35        const drift = Math.sin(t * Math.PI * 1.6 + 0.4) * 18;
36        const yJitter = (rand() - 0.5) * 16;
37        const xJitter = (rand() - 0.5) * ((endX - startX) / count) * 0.35;
38        points.push({
39            x: startX + (endX - startX) * t + xJitter,
40            y: startY + (endY - startY) * t + drift + yJitter,
41        });
42    }
43    return points;
44};
45
46const handDrawnTrendlinePoints = generateHandDrawnTrendline();
47
48type TInitialFreehandAnnotation = {
49    points: { x: number; y: number }[];
50    stroke: string;
51    strokeThickness: number;
52};
53
54const initialFreehandAnnotations: TInitialFreehandAnnotation[] = [
55    {
56        points: [
57            { x: 1705074424.9760892, y: 65731.6718827903 },
58            { x: 1705075600.6684432, y: 65642.12282942746 },
59            { x: 1705087445.885085, y: 65307.71857034999 },
60            { x: 1705085666.0820355, y: 65356.5315837517 },
61            { x: 1705081130.604812, y: 65410.78777490682 },
62            { x: 1705070214.7892404, y: 65438.14998565657 },
63            { x: 1705086971.8905394, y: 65356.648641337786 },
64            { x: 1705090526.8496335, y: 65388.83947751397 },
65            { x: 1705094908.9756804, y: 65460.77136416947 },
66            { x: 1705091521.3087788, y: 65449.416778318235 },
67        ],
68        stroke: "#F97066",
69        strokeThickness: 4,
70    },
71    {
72        points: [
73            { x: 1705025064.4852417, y: 66127.82401853298 },
74            { x: 1705025394.4226215, y: 65871.17526101925 },
75            { x: 1705024855.3700008, y: 65954.7251130947 },
76            { x: 1705029753.3136415, y: 65982.08732384446 },
77            { x: 1705035097.3697963, y: 65992.00795426602 },
78            { x: 1705040343.8388386, y: 65986.09654616822 },
79            { x: 1705044791.0229604, y: 65964.20677756841 },
80            { x: 1705045278.9585223, y: 65933.80106958018 },
81            { x: 1705043201.74713, y: 65906.67297400262 },
82            { x: 1705035543.48231, y: 65873.80905670639 },
83            { x: 1705027936.3345492, y: 65859.3231804271 },
84            { x: 1705022132.2248645, y: 65859.11832965145 },
85        ],
86        stroke: "#F97066",
87        strokeThickness: 4,
88    },
89    {
90        points: [
91            { x: 1705060251.609766, y: 65972.86903893946 },
92            { x: 1705060688.4282691, y: 65910.50660994725 },
93            { x: 1705065716.4880598, y: 65861.5180101664 },
94            { x: 1705069043.7438917, y: 65854.55308379373 },
95            { x: 1705070656.2547488, y: 65860.55228508111 },
96            { x: 1705072877.523307, y: 65910.76998951596 },
97            { x: 1705073388.6938958, y: 65974.47858074827 },
98            { x: 1705080935.4305873, y: 65866.11252042063 },
99        ],
100        stroke: "#F97066",
101        strokeThickness: 4,
102    },
103    {
104        points: [
105            { x: 1705091646.7779233, y: 65990.3691480607 },
106            { x: 1705091860.5401695, y: 65928.09451225805 },
107            { x: 1705094035.338674, y: 65896.19632004711 },
108            { x: 1705100819.966488, y: 65890.43123393191 },
109            { x: 1705104123.987293, y: 65914.89626942581 },
110            { x: 1705104742.0390048, y: 65990.60326323289 },
111            { x: 1705105169.5634973, y: 65837.34561863774 },
112            { x: 1705103979.9301271, y: 65712.03547272283 },
113            { x: 1705100095.033653, y: 65693.04287937887 },
114            { x: 1705092195.1245549, y: 65700.32971411331 },
115            { x: 1705088156.876904, y: 65734.97875959748 },
116            { x: 1705088291.6400592, y: 65779.40211352061 },
117            { x: 1705102172.2450452, y: 65854.20191103544 },
118            { x: 1705112846.4163384, y: 65896.78160797758 },
119        ],
120        stroke: "#F97066",
121        strokeThickness: 4,
122    },
123    {
124        points: [
125            { x: 1705271913.4095333, y: 68272.31899579709 },
126            { x: 1705254473.1984477, y: 68281.71286708124 },
127            { x: 1705243325.0326085, y: 68256.80886563948 },
128            { x: 1705241071.2350128, y: 68237.43583514073 },
129            { x: 1705240253.362071, y: 68204.68897543059 },
130            { x: 1705263358.2726805, y: 68162.25560047108 },
131            { x: 1705266676.2345016, y: 68137.556449805 },
132            { x: 1705266866.7617211, y: 68104.31209535395 },
133            { x: 1705263558.0939107, y: 68079.99338184268 },
134            { x: 1705255137.720213, y: 68056.46480703754 },
135            { x: 1705245188.4817545, y: 68058.92301634554 },
136            { x: 1705237929.859395, y: 68076.89135581115 },
137        ],
138        stroke: "#4EC385",
139        strokeThickness: 4,
140    },
141    {
142        points: [
143            { x: 1705282146.115318, y: 68129.39168317485 },
144            { x: 1705292318.4100335, y: 68129.39168317485 },
145            { x: 1705293675.335596, y: 68157.39771064813 },
146            { x: 1705293670.6885908, y: 68187.07180872327 },
147            { x: 1705292443.8791778, y: 68194.03673509593 },
148            { x: 1705280305.9011989, y: 68194.82687380207 },
149            { x: 1705275919.1281466, y: 68183.64787432998 },
150            { x: 1705274227.6181984, y: 68106.59471828281 },
151            { x: 1705277666.402159, y: 68075.6037223641 },
152            { x: 1705283721.4501324, y: 68055.26496678006 },
153            { x: 1705292304.4690173, y: 68053.74321816083 },
154            { x: 1705297546.2910542, y: 68064.07355013373 },
155        ],
156        stroke: "#4EC385",
157        strokeThickness: 4,
158    },
159    {
160        points: [
161            { x: 1705314953.9731023, y: 68304.74394714547 },
162            { x: 1705314517.1545992, y: 68072.50169633258 },
163        ],
164        stroke: "#4EC385",
165        strokeThickness: 4,
166    },
167    {
168        points: [
169            { x: 1705332956.4718356, y: 68300.50060964952 },
170            { x: 1705332956.4718356, y: 68178.23396097307 },
171            { x: 1705330897.8484647, y: 68051.95808997288 },
172        ],
173        stroke: "#4EC385",
174        strokeThickness: 4,
175    },
176    {
177        points: [
178            { x: 1705294609.3836718, y: 67929.01836017639 },
179            { x: 1705294474.6205165, y: 67825.6272472578 },
180            { x: 1705285682.4863908, y: 67528.6814157308 },
181            { x: 1705283005.8113081, y: 67676.43735377946 },
182            { x: 1705285306.0789573, y: 67543.25508519965 },
183            { x: 1705300334.4942653, y: 67679.27600024227 },
184        ],
185        stroke: "#4EC385",
186        strokeThickness: 4,
187    },
188];
189
190const variantOptions = (variant: TFreehandVariant, background: string): IFreehandDrawingAnnotationOptions => {
191    const base: IFreehandDrawingAnnotationOptions = {
192        isEditable: true,
193        strokeThickness: 4,
194        showBoxOutline: false,
195        boxOutlineStrokeDashArray: [6, 4],
196        snapMode: ESnapMode.None,
197        annotationsGripsRadius: 4,
198        gripSvgTemplate: (annotation: any, x: number, y: number) => {
199            const ann = annotation as FreehandDrawingAnnotation;
200            return `<circle cx="${x}" cy="${y}" r="${ann.annotationsGripsRadius}" fill="${background}" stroke="${ann.annotationsGripsStroke}" stroke-width="${ann.strokeThickness}" />`;
201        },
202    };
203
204    switch (variant) {
205        case "editableOutline":
206            return {
207                ...base,
208                stroke: TRADING_ANNOTATION_COLORS.freehand,
209                annotationsGripsStroke: TRADING_ANNOTATION_COLORS.freehand,
210                allowMove: true,
211                showBoxOutlineOnlyWhenSelected: false,
212            };
213        case "locked":
214            return {
215                ...base,
216                stroke: TRADING_ANNOTATION_COLORS.lockedFreehand,
217                annotationsGripsStroke: TRADING_ANNOTATION_COLORS.lockedFreehand,
218                keepAspectRatioOnResize: true,
219                forcedAspectRatio: 1,
220                showBoxOutlineOnlyWhenSelected: false,
221            };
222        case "nonEditableLine":
223            return {
224                ...base,
225                isEditable: false,
226                isSelected: false,
227                stroke: TRADING_ANNOTATION_COLORS.foreground,
228                strokeThickness: 2,
229                showBoxOutline: false,
230                gripVisibility: EAnnotationVisibilityMode.OnInteraction,
231                allowMove: false,
232                showBoxOutlineOnlyWhenSelected: false,
233            };
234        case "thickHighlight":
235            return {
236                ...base,
237                stroke: TRADING_ANNOTATION_COLORS.warning,
238                fill: `${TRADING_ANNOTATION_COLORS.warning}33`,
239                annotationsGripsStroke: TRADING_ANNOTATION_COLORS.warning,
240                strokeThickness: 4,
241                showBoxOutlineOnlyWhenSelected: false,
242            };
243    }
244};
245
246export const drawExample = async (rootElement: string | HTMLDivElement) => {
247    const { sciChartSurface, xAxis } = await createFinancialChart(rootElement, {
248        volatility: 0.0023,
249        title: "BTC / USDT - Freehand Drawing",
250        startDate: new Date("2024-01-01T00:00:00Z"),
251        dataSeed: 2024,
252    });
253
254    // Jan 20 2024 00:00 UTC
255    xAxis.visibleRange = new NumberRange(xAxis.visibleRange.min, 1705708800);
256
257    const freehandDrawingModifier = new FreehandDrawingModifier({
258        isDrawing: false,
259        keepDrawingAfterComplete: true,
260        pointSamplingDistancePx: 1.2,
261        simplifyTolerancePx: 0.8,
262        maxPoints: 6000,
263    });
264
265    sciChartSurface.chartModifiers.add(
266        new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
267        new ZoomExtentsModifier({ xyDirection: EXyDirection.XDirection }),
268        new AnnotationHoverModifier({
269            enableHover: true,
270            enableCursor: true,
271            idleCursor: ECursorStyle.Crosshair,
272        }),
273        freehandDrawingModifier
274    );
275
276    sciChartSurface.annotations.add(
277        ...initialFreehandAnnotations.map(
278            (data) =>
279                new FreehandDrawingAnnotation({
280                    points: data.points,
281                    stroke: data.stroke,
282                    strokeThickness: data.strokeThickness,
283                    isEditable: true,
284                    isSelected: false,
285                    allowMove: true,
286                    showBoxOutline: false,
287                    opacity: 0.9,
288                    gripVisibility: EAnnotationVisibilityMode.OnInteraction,
289                })
290        ),
291        new FreehandDrawingAnnotation({
292            points: handDrawnTrendlinePoints,
293            isEditable: true,
294            isSelected: false,
295            allowMove: true,
296            showBoxOutline: false,
297            stroke: "#686c70",
298            annotationsGripsStroke: "#9AA0A6",
299            strokeThickness: 7,
300            opacity: 0.9,
301            gripVisibility: EAnnotationVisibilityMode.OnInteraction,
302        })
303    );
304
305    return {
306        sciChartSurface,
307        startDrawing: (variant: TFreehandVariant, color?: string) => {
308            const options = variantOptions(variant, sciChartSurface.background);
309            if (color) {
310                options.stroke = color;
311                options.annotationsGripsStroke = color;
312            }
313            freehandDrawingModifier.startDrawing(options);
314        },
315        stopDrawing: () => freehandDrawingModifier.stopDrawing(true),
316        clear: () => sciChartSurface.annotations.clear(true),
317        removeLast: () => {
318            const annotations = sciChartSurface.annotations;
319            if (annotations.size() > 0) {
320                annotations.removeAt(annotations.size() - 1, true);
321            }
322        },
323        exportAnnotations: () =>
324            sciChartSurface.annotations
325                .asArray()
326                .filter((a): a is FreehandDrawingAnnotation => a instanceof FreehandDrawingAnnotation)
327                .map((a) => ({
328                    points: a.points.map((p) => ({ x: p.x, y: p.y })),
329                    stroke: a.stroke,
330                    strokeThickness: a.strokeThickness,
331                })),
332        setKeepDrawingAfterComplete: (enabled: boolean) => {
333            (freehandDrawingModifier as any).keepDrawingAfterCompleteProperty = enabled;
334        },
335        setSampling: (pointSamplingDistancePx: number, simplifyTolerancePx: number, maxPoints: number) => {
336            freehandDrawingModifier.pointSamplingDistancePx = pointSamplingDistancePx;
337            (freehandDrawingModifier as any).simplifyTolerancePxProperty = simplifyTolerancePx;
338            (freehandDrawingModifier as any).maxPointsProperty = maxPoints;
339        },
340    };
341};
342

angular Chart Examples & Demos

See Also: Financial Charts (11 Demos)

Angular Candlestick Chart | Online JavaScript Chart Examples

Angular Candlestick Chart

Discover how to create a Angular Candlestick Chart or Stock Chart using SciChart.js. For high Performance JavaScript Charts, get your free demo now.

Angular OHLC Chart | Angular Charts | SciChart.js Demo

Angular OHLC Chart

Easily create Angular OHLC Chart or Stock Chart using feature-rich SciChart.js chart library. Supports custom colors. Get your free trial now.

Angular Realtime Ticking Stock Chart | SciChart.js Demo

Angular Realtime Ticking Stock Charts

Create a Angular Realtime Ticking Candlestick / Stock Chart with live ticking and updating, using the high performance SciChart.js chart library. Get free demo now.

NEW!
Angular Orderbook Heatmap | Angular Charts | SciChart.js Demo

Angular Orderbook Heatmap

Create an Angular heatmap chart showing historical orderbook levels, using the high performance SciChart.js chart library. Get free demo now.

Angular Multi-Pane Stock Chart using Subcharts | View JavaScript Charts

Angular Multi-Pane Stock Charts using Subcharts

Create a Angular Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

Tenor Curves Demo | Angular Charts | SciChart.js Demo

Tenor Curves Demo

Demonstrating the capability of SciChart.js to create a composite 2D &amp; 3D Chart application. An example like this could be used to visualize Tenor curves in a financial setting, or other 2D/3D data combined on a single screen.

Angular Multi-Pane Stock Chart | View JavaScript Charts

Angular Multi-Pane Stock Charts using Sync Multi-Chart

Create a Angular Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

Angular Market Depth Chart | Angular Charts | SciChart.js

Angular Market Depth Chart

Create a Angular Depth Chart, using the high performance SciChart.js chart library. Get free demo now.

Angular Chart Hoverable Buy Sell Marker Annotations

Angular Chart Hoverable Buy Sell Marker Annotations

Demonstrates how to place Buy/Sell arrow markers on a Angular Stock Chart using SciChart.js - Annotations API

Angular User Annotated Stock Chart | SciChart.js Demo

Angular User Annotated Stock Chart

This demo shows you how to create a <strong>{frameworkName} User Annotated Stock Chart</strong> using SciChart.js. Custom modifiers allow you to add lines and markers, then use the built in serialisation functions to save and reload the chart, including the data and all your custom annotations.

NEW!
 | Angular Charts | SciChart.js Demo

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.