openalgo-charts 2.5.1 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { AlertDrawingValue, AlertDrawingLevel, PrimitiveRenderContext, IPrimitive, PrimitiveHost, ZOrder, PrimitiveHit, DataLayer, AlertDrawingInfo } from 'openalgo-charts';
1
+ import { AlertDrawingValue, AlertDrawingLevel, PrimitiveRenderContext, Bar, IPrimitive, DataLayer, AlertDrawingInfo, PrimitiveHost, ZOrder, PrimitiveHit } from 'openalgo-charts';
2
2
 
3
3
  /**
4
4
  * The per-tool settings schema: what a host may show in a drawing's settings
@@ -35,6 +35,8 @@ interface SettingsField {
35
35
  label: string;
36
36
  }>;
37
37
  group?: FieldGroup;
38
+ /** Value displayed when the drawing has not overridden this setting. */
39
+ defaultValue?: string | number | boolean;
38
40
  }
39
41
  interface SettingsSchema {
40
42
  fields: SettingsField[];
@@ -111,9 +113,8 @@ declare function composeSettings(parts: ReadonlyArray<readonly SettingsField[] |
111
113
  /** The value at a dot path, or `undefined` when unset or the path is not one the model has. */
112
114
  declare function readDrawingSetting(d: Drawing, path: string): unknown;
113
115
  /**
114
- * Every field of a schema read off a drawing, keyed by path. Absent values
115
- * are present as `undefined`, so a host can iterate the schema and render
116
- * each control in its "default" state rather than guessing.
116
+ * Every field of a schema read off a drawing, keyed by path. Unset fields use
117
+ * their declared default value, or remain `undefined` when no default exists.
117
118
  */
118
119
  declare function readDrawingSettings(d: Drawing, schema: SettingsSchema): Record<string, unknown>;
119
120
  /**
@@ -424,775 +425,222 @@ interface DrawingTool {
424
425
  distance(x: number, y: number, c: HitContext): number | null;
425
426
  }
426
427
 
427
- /**
428
- * Built-in drawing tools + the tool registry. Same philosophy as the chart-type
429
- * and indicator registries: a tool is a descriptor, the layer just runs it, and
430
- * `registerDrawingTool` makes a custom one first-class.
431
- *
432
- * `draw` receives anchors already in device px; `distance` receives them in
433
- * media px, the same space as the incoming cursor.
434
- *
435
- * Text lives in `drawing.text` (a `DrawingText`), never in the style bag: a
436
- * shape's outline colour and its label colour are two decisions, and a tool
437
- * that prints only a readout (a fib ladder, a measure chip) still reads its
438
- * face from there. Ladders read `FibLevel[]` and stroke each level in its own
439
- * colour, taken from the shared palette in levels.ts.
440
- *
441
- * Every tool declares `settings`: the fields a host may show for it. The
442
- * schema is a contract, not a wish list. A field is declared only when this
443
- * file reads it, because a control with nothing behind it is a defect.
444
- */
428
+ /** Time-anchored analysis drawings use the owning pane's bars, never a tier cache. */
445
429
 
446
- declare function registerDrawingTool(tool: DrawingTool): void;
447
- declare function getDrawingTool(id: string): DrawingTool;
448
- declare function hasDrawingTool(id: string): boolean;
449
- declare function registeredDrawingTools(): DrawingTool[];
450
- /** Keyboard event fields a shortcut is matched against. */
451
- interface ShortcutEvent {
452
- key: string;
453
- altKey?: boolean;
454
- ctrlKey?: boolean;
455
- metaKey?: boolean;
456
- shiftKey?: boolean;
430
+ declare const ANCHORED_VWAP: DrawingTool;
431
+ declare const FIXED_RANGE_VOLUME_PROFILE: DrawingTool;
432
+
433
+ /** Pure OHLCV analysis. Inputs are sorted by ascending UTC timestamp. */
434
+
435
+ /** Partial results have unavailable anchor history, missing volume or unusable prices. */
436
+ type AnalysisStatus = 'ready' | 'partial' | 'missing-volume' | 'zero-volume' | 'empty' | 'invalid-data';
437
+ type AnchoredVwapSource = 'hlc3' | 'close' | 'hl2' | 'ohlc4';
438
+ interface AnchoredVwapOptions {
439
+ source?: AnchoredVwapSource;
440
+ }
441
+ interface AnchoredVwapPoint {
442
+ time: number;
443
+ value: number;
444
+ /** Volume-weighted population standard deviation of the selected source. */
445
+ deviation: number;
446
+ /** Do not connect a line across an omitted observation. */
447
+ breakBefore: boolean;
448
+ }
449
+ interface AnchoredVwapResult {
450
+ status: AnalysisStatus;
451
+ /** The requested anchor precedes the earliest supplied bar. */
452
+ historyPartial: boolean;
453
+ points: AnchoredVwapPoint[];
454
+ missingVolumeBars: number;
455
+ invalidPriceBars: number;
456
+ }
457
+ interface FixedRangeVolumeProfileOptions {
458
+ /** Requested price rows, rounded and clamped to 4..200. Fewer rows are used when prices cannot represent distinct edges. Default 48. */
459
+ rows?: number;
460
+ /** Percentage of volume in the contiguous area around the POC, 1..100. Default 70. */
461
+ valueArea?: number;
462
+ }
463
+ interface AnalysisProfileRow {
464
+ low: number;
465
+ high: number;
466
+ volume: number;
467
+ valueArea: boolean;
468
+ }
469
+ interface FixedRangeVolumeProfileResult {
470
+ status: AnalysisStatus;
471
+ /** The requested range begins before the earliest supplied bar. */
472
+ historyPartial: boolean;
473
+ rows: AnalysisProfileRow[];
474
+ totalVolume: number;
475
+ /** Midpoint of the largest row. Ties choose the lower price. */
476
+ poc: number | null;
477
+ valueAreaLow: number | null;
478
+ valueAreaHigh: number | null;
479
+ missingVolumeBars: number;
480
+ invalidPriceBars: number;
457
481
  }
458
482
  /**
459
- * The id of the tool whose `shortcut` matches this key event, or `null`.
460
- *
461
- * Pure, so a host can bind one `keydown` listener and decide for itself when
462
- * shortcuts apply. The library installs no listener, because only the host
463
- * knows whether the chart has focus, a dialog is open, or the user is typing.
464
- *
465
- * Modifiers must match exactly: `Alt+T` will not fire for `Ctrl+Alt+T`, so a
466
- * tool shortcut cannot shadow a browser or host chord. `metaKey` (Cmd) is
467
- * treated as Ctrl, which is what a Mac user expects.
468
- */
469
- declare function matchDrawingShortcut(e: ShortcutEvent): string | null;
470
- /** Every registered tool that has a shortcut, as `id -> shortcut`. */
471
- declare function drawingShortcuts(): Record<string, string>;
472
- /**
473
- * The settings a host may show for a tool: the tool's own declaration, else
474
- * the line fields, which every stroked custom tool reads. This is a registry
475
- * lookup, which is why it lives here and not in schema.ts: that module stays
476
- * free of any import that could loop back into this one.
477
- */
478
- declare function drawingSettingsSchema(toolId: string): SettingsSchema;
479
- declare const TREND_LINE: DrawingTool;
480
- declare const RAY: DrawingTool;
481
- declare const EXTENDED_LINE: DrawingTool;
482
- declare const ARROW: DrawingTool;
483
- declare const HORIZONTAL_LINE: DrawingTool;
484
- declare const HORIZONTAL_RAY: DrawingTool;
485
- declare const VERTICAL_LINE: DrawingTool;
486
- declare const CROSS_LINE: DrawingTool;
487
- declare const RECTANGLE: DrawingTool;
488
- declare const ELLIPSE: DrawingTool;
489
- declare const PARALLEL_CHANNEL: DrawingTool;
490
- declare const FIB_RETRACEMENT: DrawingTool;
491
- declare const FIB_EXTENSION: DrawingTool;
492
- declare const MEASURE: DrawingTool;
493
- declare const LONG_POSITION: DrawingTool;
494
- declare const SHORT_POSITION: DrawingTool;
495
- declare const TEXT: DrawingTool;
496
- /**
497
- * Path: click each vertex, double-click to finish, arrowhead on the last leg.
498
- * The arrow is what separates it from `polyline`: a path points somewhere.
499
- */
500
- declare const PATH: DrawingTool;
501
- /**
502
- * Brush: freehand ink. Press, drag, release. The anchors are the thinned
503
- * samples of the gesture and the spline between them is what is stroked, so
504
- * the ink stays a curve after the thinning that keeps a stroke small.
483
+ * Accumulate from the first bar at or after the anchor, including the live tail.
484
+ * Missing volume is omitted and reported; zero volume adds no statistical weight.
485
+ * Recompute on each call so mutations of the forming candle are always visible.
505
486
  */
506
- declare const BRUSH: DrawingTool;
487
+ declare function anchoredVwapAnalysis(bars: readonly Bar[], anchorTime: number, options?: AnchoredVwapOptions): AnchoredVwapResult;
507
488
  /**
508
- * Rotated rectangle: anchors 0 and 1 lay out one edge (and so the rotation),
509
- * and anchor 2 sets the depth perpendicular to it. An axis-aligned `rectangle`
510
- * cannot follow a trend channel; this can.
489
+ * Estimate a volume histogram over the inclusive timestamp range. Each candle's
490
+ * volume is uniform over low..high; this is not trade-by-trade volume. Difference
491
+ * arrays distribute interior rows without visiting each row per candle. Row
492
+ * lookup is bounded by 200 edges: O(bars log(rows) + rows).
511
493
  */
512
- declare const ROTATED_RECTANGLE: DrawingTool;
494
+ declare function fixedRangeVolumeProfileAnalysis(bars: readonly Bar[], fromTime: number, toTime: number, options?: FixedRangeVolumeProfileOptions): FixedRangeVolumeProfileResult;
495
+
513
496
  /**
514
- * Double curve: an S through three anchors. `curve` bends one way off a single
515
- * control; this mirrors that control about the midpoint so the second half bends
516
- * back, which is the shape a rounded top-then-bottom actually needs.
497
+ * Clipboard transfer for drawings: the layer between the drawing model and the
498
+ * OS clipboard.
499
+ *
500
+ * Two things make this more than `JSON.stringify`:
501
+ *
502
+ * 1. **The OS clipboard is shared with everything else on the machine.** A
503
+ * paste can arrive from a spreadsheet, another application, or a hand-edited
504
+ * copy of our own payload. So the payload is written under a namespaced key
505
+ * and everything read back is validated field by field before it can reach
506
+ * the model. Foreign text is *not ours* and is ignored, never an exception
507
+ * the host has to catch on every Ctrl+V.
508
+ * 2. **Clipboard access is async and permission-gated.** `navigator.clipboard`
509
+ * rejects when the document is not focused, the page is not secure, or the
510
+ * user denied the permission. Copy must still work inside the tab, so every
511
+ * write also lands in a module-level in-memory clipboard which is shared by
512
+ * every controller in the page. That is what makes chart-to-chart paste work
513
+ * with the permission denied, and it is why the memory store is a singleton
514
+ * rather than per-controller state.
515
+ *
516
+ * The payload body is a drawings document (`DrawingsDocument`), so a copy made
517
+ * by a 1.9.x build (a version 1 body carrying the old style-bag text fields)
518
+ * is upgraded by the same migration a saved layout goes through.
517
519
  */
518
- declare const DOUBLE_CURVE: DrawingTool;
520
+
519
521
  /**
520
- * Cyclic lines: vertical lines repeating at the interval the two anchors set,
521
- * for reading a rhythm forward off a measured swing.
522
+ * Top-level key of the JSON payload. Namespaced so a paste of arbitrary text,
523
+ * or of JSON belonging to some other application, is recognisable as not ours
524
+ * by looking at one property.
522
525
  */
523
- declare const CYCLIC_LINES: DrawingTool;
526
+ declare const DRAWING_CLIPBOARD_KEY = "openalgo-charts/drawings";
524
527
  /**
525
- * Time cycles: semicircles of the anchors' width repeating along the axis, the
526
- * classic cycle-projection overlay.
528
+ * Payload format version. Tracks the model version, since the body *is* a
529
+ * drawings document: version 1 carried 1.9.x drawings, version 2 carries the
530
+ * split text and levelled fibs.
527
531
  */
528
- declare const TIME_CYCLES: DrawingTool;
532
+ declare const DRAWING_CLIPBOARD_VERSION: number;
533
+ /** The async slice of `navigator.clipboard` this module uses. */
534
+ interface ClipboardPort {
535
+ writeText(text: string): Promise<void>;
536
+ readText(): Promise<string>;
537
+ }
538
+ /** Test seam: drop whatever the in-memory clipboard is holding. */
539
+ declare function clearMemoryClipboard(): void;
540
+ /** `navigator.clipboard` when the browser exposes it, else null. */
541
+ declare function systemClipboard(): ClipboardPort | null;
542
+ /** Deep copy of the persisted fields, so a clone shares nothing with its source. */
543
+ declare function cloneDrawing(d: Drawing): Drawing;
544
+ /** Serialise drawings into the namespaced payload written to the clipboard. */
545
+ declare function encodeClipboardPayload(drawings: readonly Drawing[]): string;
529
546
  /**
530
- * Sine line: a full wave between the anchors. The horizontal span is one
531
- * period, the vertical offset its amplitude.
547
+ * Validate one entry into a drawing with no id. Returns null for anything that
548
+ * cannot be rendered: an unknown tool would throw inside the controller, and a
549
+ * NaN anchor produces a drawing that can never be drawn or hit-tested again.
550
+ * Accepts the 1.9.x shape too, lifting its text fields into `text`.
532
551
  */
533
- declare const SINE_LINE: DrawingTool;
552
+ declare function sanitizeDrawing(value: unknown): Omit<Drawing, 'id'> | null;
534
553
  /**
535
- * Price label: a pill of the anchored price with a tail pointing at the bar.
536
- * Reads its value off the anchor, so dragging it re-reads rather than going
537
- * stale the way a typed-in text would. Text, when given, replaces the price.
554
+ * Parse clipboard text into drawings, or null when the text is not ours or is
555
+ * not usable. All-or-nothing on purpose: a payload with one corrupt entry is a
556
+ * corrupt payload, and pasting the other nine silently would be worse than
557
+ * pasting none.
538
558
  */
539
- declare const PRICE_LABEL: DrawingTool;
559
+ declare function decodeClipboardPayload(text: unknown): Omit<Drawing, 'id'>[] | null;
560
+ interface DrawingClipboardOptions {
561
+ /** Where to read and write. Defaults to `navigator.clipboard` when present. */
562
+ port?: ClipboardPort | null;
563
+ /**
564
+ * Keep a copy in the shared in-memory clipboard so copy and paste keep
565
+ * working when the OS clipboard is unavailable or the permission is refused.
566
+ * Default true. Set false to make a failed system write a failed copy, which
567
+ * a host that must not silently lose cross-tab transfer may prefer.
568
+ */
569
+ fallbackToMemory?: boolean;
570
+ }
540
571
  /**
541
- * Callout: a text bubble on its own anchor with a tail back to the point it
542
- * annotates, so the note can sit clear of the price action it refers to.
572
+ * The clipboard as the controller sees it: drawings in, drawings out, no
573
+ * exceptions escaping. Every failure mode (no clipboard API, refused
574
+ * permission, foreign text, corrupt payload) reduces to `false` or `null`.
543
575
  */
544
- declare const CALLOUT: DrawingTool;
545
- /** Flag mark: a pennant on a pole at one anchor, for tagging a bar. */
546
- declare const FLAG_MARK: DrawingTool;
576
+ declare class DrawingClipboard {
577
+ private _port;
578
+ private _fallback;
579
+ /** Why the last operation did not reach the OS clipboard, if it did not. */
580
+ private _lastError;
581
+ constructor(options?: DrawingClipboardOptions);
582
+ /** Swap the port at runtime (a host granting permission later, or a test). */
583
+ setPort(port: ClipboardPort | null): void;
584
+ /**
585
+ * Turn the in-memory backstop off or on. With it off, a refused system write
586
+ * is a failed copy, which is what a host wants when a cut that cannot reach
587
+ * the OS clipboard must not delete the drawing.
588
+ */
589
+ setFallbackToMemory(enabled: boolean): void;
590
+ /**
591
+ * Why the OS clipboard was not used by the last call, or null when it was.
592
+ * Set on a successful copy too, when the payload reached memory but not the
593
+ * system clipboard: that copy works in this tab and will not appear in
594
+ * another, which is exactly what a host wants to be able to tell the user.
595
+ */
596
+ lastError(): string | null;
597
+ /**
598
+ * Write drawings out. Resolves true when the payload is retrievable by a
599
+ * later `read()` (through the system clipboard, or through memory when the
600
+ * fallback is on), false when it is not, so a caller doing a cut knows
601
+ * whether it is safe to delete the original.
602
+ */
603
+ write(drawings: readonly Drawing[]): Promise<boolean>;
604
+ /**
605
+ * Read drawings back, or null when there is nothing of ours to paste. The
606
+ * system clipboard wins when it holds our payload, so a copy made in another
607
+ * tab beats a stale in-tab one; memory is consulted when the read fails or
608
+ * returns something that is not ours. That last case can paste an older copy
609
+ * after the user has copied unrelated text elsewhere, which is the deliberate
610
+ * trade: losing the copy whenever a browser refuses the read half of the
611
+ * permission would be the worse surprise.
612
+ */
613
+ read(): Promise<Omit<Drawing, 'id'>[] | null>;
614
+ }
615
+
547
616
  /**
548
- * Note: a pin at the bar with its text to the upper right.
617
+ * Drawing controller: the interaction and persistence layer over
618
+ * `DrawingLayer`. It is **headless**: no DOM, no toolbar. A host sets the
619
+ * active tool (from its own button, a shortcut, a command palette) and the
620
+ * controller runs placement, selection, dragging, undo, and serialisation.
549
621
  *
550
- * The pin is the point being annotated and the plate is the annotation, which
551
- * is why the two are drawn as separate marks joined by a stem rather than as
552
- * one bubble: the reader needs to see exactly which bar is meant, and a bubble
553
- * wide enough to hold a sentence covers several.
554
- */
555
- declare const NOTE: DrawingTool;
556
- /**
557
- * Balloon: a speech bubble sitting above its anchor, tail pointing down.
622
+ * It listens on the chart's event bus (`click`, `crosshair:move`, `drag`,
623
+ * `drag:end`) rather than the single-slot `subscribeClick`/`subscribeDrag`
624
+ * callbacks, so a host keeps using those for its own order lines.
558
625
  *
559
- * One anchor rather than the callout's two: a balloon is for saying something
560
- * *about this bar*, so letting the bubble be dragged away from what it labels
561
- * would only invite it to drift.
626
+ * Selection is a list. Every method that edits takes the whole list into one
627
+ * undo entry, so a multi-drag, a batch delete or a paste of ten shapes is one
628
+ * Ctrl+Z, which is what the hand that did it expects.
562
629
  */
563
- declare const BALLOON: DrawingTool;
630
+
564
631
  /**
565
- * Comment: a small square-cornered box with a tail off its bottom left.
632
+ * The slice of the chart this controller needs.
566
633
  *
567
- * Deliberately plainer than the balloon: a chart that says something at every
568
- * other bar needs one of these marks to be quiet, and the shape is the only
569
- * thing distinguishing them once both are the user's own colour.
570
- */
571
- declare const COMMENT: DrawingTool;
572
- /**
573
- * Signpost: a post standing on the bar with its plate at the top.
574
- *
575
- * The one annotation anchored to *time* rather than to a level: the post is
576
- * vertical so the plate can clear the price action entirely while the foot
577
- * still names an exact bar. Useful for events, which happen at a moment and
578
- * not at a price.
579
- */
580
- declare const SIGNPOST: DrawingTool;
581
- /**
582
- * Price note: the anchored price, with the user's text under it.
583
- *
584
- * The price is read off the anchor rather than typed, so dragging the note
585
- * re-reads it. A typed price is a number that was true once, which on a chart
586
- * is worse than no number at all.
587
- */
588
- declare const PRICE_NOTE: DrawingTool;
589
- /**
590
- * Table: rows of text in a grid, anchored top-left.
591
- *
592
- * Cells come from the text: a newline starts a row and a pipe separates
593
- * columns, so a whole table is one editable string and survives `getState`
594
- * with no new shape in the drawing model. The first row is drawn as a header
595
- * because a table on a chart is nearly always labelled.
596
- */
597
- declare const TABLE: DrawingTool;
598
- /**
599
- * Measurers. `measure` reports price *and* time together; these two constrain it
600
- * to one axis, which is what you want when the other one is noise: sizing a
601
- * retracement without caring how long it took, or counting bars to an event
602
- * without caring where price went.
603
- */
604
- declare const PRICE_RANGE: DrawingTool;
605
- declare const DATE_RANGE: DrawingTool;
606
- /**
607
- * Position forecast: project a move from an anchor. Two anchors give the
608
- * projected leg; the shape extends the same slope past the target as a dashed
609
- * cone, so the drawing says "if this continues" rather than just marking a line.
610
- */
611
- declare const FORECAST: DrawingTool;
612
- /**
613
- * Circle from centre + a radius handle. The radius is measured in *pixels*, so
614
- * it stays a circle on screen instead of the ellipse the two axes' differing
615
- * scales would otherwise produce.
616
- */
617
- declare const CIRCLE: DrawingTool;
618
- declare const TRIANGLE: DrawingTool;
619
- /** Free-form polyline: click each vertex, double-click to finish. */
620
- declare const POLYLINE: DrawingTool;
621
- /** Arc through three anchors: the middle one is on the curve, not a handle. */
622
- declare const ARC: DrawingTool;
623
- /** Quadratic curve: the middle anchor is a control handle, off the curve. */
624
- declare const CURVE: DrawingTool;
625
- declare const ARROW_UP: DrawingTool;
626
- declare const ARROW_DOWN: DrawingTool;
627
- declare const ARROW_LEFT: DrawingTool;
628
- declare const ARROW_RIGHT: DrawingTool;
629
- /** Highlighter: the brush with a fat, translucent stroke. */
630
- declare const HIGHLIGHTER: DrawingTool;
631
- /** Fib channel: fib levels spread across a trend leg, parallel to it. */
632
- declare const FIB_CHANNEL: DrawingTool;
633
- /**
634
- * Fib time zone: vertical lines at Fibonacci multiples of the base leg's width.
635
- * Its levels count bars rather than divide a leg, so they carry no convention
636
- * colour and fall back to the drawing's own.
637
- */
638
- declare const FIB_TIME_ZONE: DrawingTool;
639
- /** Rays from the anchor at fib fractions of the leg: the speed resistance fan. */
640
- declare const FIB_FAN: DrawingTool;
641
- /**
642
- * Gann fan: rays from one anchor at the classic price/time angles. A level's
643
- * ratio is price per unit of time, so the 1x1 is 1, the 1x2 is 0.5 and the
644
- * 2x1 is 2; each angle keeps its own colour from the cycle palette.
645
- */
646
- declare const GANN_FAN: DrawingTool;
647
- /**
648
- * Gann box: the drawn rectangle divided at its levels on both axes, plus the
649
- * 1x1 diagonal. Ratio 0 is the first anchor's price and time, ratio 1 the
650
- * second's, so the box reads like a retracement laid over a date range.
651
- */
652
- declare const GANN_BOX: DrawingTool;
653
- declare const BUILTIN_DRAWING_TOOLS: readonly DrawingTool[];
654
- /** Register every built-in tool. Idempotent; called on tier import. */
655
- declare function registerBuiltinDrawingTools(): void;
656
-
657
- /**
658
- * The shared level palette for the Fibonacci and Gann family.
659
- *
660
- * Every ladder tool (retracement, extension, channel, fan, time zone, the Gann
661
- * fan and box) strokes a list of ratios, and each ratio has a colour the eye
662
- * expects: 0.618 reads as one thing across every tool, not a different hue per
663
- * tool. Before this module each tool would have restated those colours, and
664
- * restated colours drift. This is the one statement; tools take their defaults
665
- * from it and hosts seed a newly added level from it.
666
- *
667
- * Pure: no DOM, no registry. Safe to import from a worker or a settings panel.
668
- */
669
-
670
- /**
671
- * The colour of a ratio that is an anchor rather than a level (0, 1, 2, 3 are
672
- * where the measured leg starts and ends, or whole multiples of it) and of any
673
- * ratio the convention does not name. Neutral on purpose: it is the reference
674
- * the coloured levels are read against.
675
- */
676
- declare const LEVEL_NEUTRAL = "#787b86";
677
- /**
678
- * The conventional colour for a Fibonacci ratio. Anchors (0, 1, 2, 3) and any
679
- * ratio without a convention come back {@link LEVEL_NEUTRAL}, so a host can call
680
- * this for every new level and always get a usable colour.
681
- */
682
- declare function levelColor(ratio: number): string;
683
- /**
684
- * A short sequence of colours that stay distinguishable side by side, for
685
- * tools whose levels are positions rather than ratios: the angles of a Gann
686
- * fan, the repeats of a cycle. Index `i` wraps, so any count is safe.
687
- */
688
- declare const CYCLE_PALETTE: readonly string[];
689
- /** The `i`th cycle colour. Wraps in both directions; a negative index is fine. */
690
- declare function cycleColor(i: number): string;
691
- /** `0.618` as `61.8%`: the text a level prints when it carries no label. */
692
- declare function formatRatio(ratio: number): string;
693
- /**
694
- * The label for a Gann angle stored as a price-per-time ratio: `1` is the 1x1,
695
- * `0.5` the 1x2, `2` the 2x1. Ratios that are not clean reciprocals fall back
696
- * to the ratio itself, which is still true, just less idiomatic.
697
- */
698
- declare function gannLabel(ratio: number): string;
699
- /** A mutable copy of a default ladder, for a fresh drawing's own `style.levels`. */
700
- declare function cloneLevels(levels: readonly FibLevel[]): FibLevel[];
701
- /** Retracement and extension: the classic ladder, coloured by convention. */
702
- declare const DEFAULT_FIB: readonly FibLevel[];
703
- /** Speed fan: rays at the fractions of the leg. No 0 ray, it would be flat. */
704
- declare const DEFAULT_FIB_FAN: readonly FibLevel[];
705
- /** Gann box: quarters plus the golden pair, applied to both axes of the box. */
706
- declare const DEFAULT_GANN_BOX: readonly FibLevel[];
707
- /**
708
- * Gann fan: the classic angles as price-per-time ratios, 1x8 up to 8x1. These
709
- * are positions in a sequence rather than Fibonacci ratios, so they take the
710
- * cycle palette.
711
- */
712
- declare const DEFAULT_GANN_FAN: readonly FibLevel[];
713
- /**
714
- * Time zones count bars along the Fibonacci sequence, so `ratio` here is a
715
- * multiple of the anchor leg, not a fraction of it. No colour is set: there is
716
- * no convention for "the 13 line", so every zone takes the drawing's own colour
717
- * until the user gives one its own.
718
- */
719
- declare const DEFAULT_FIB_TIME_ZONE: readonly FibLevel[];
720
-
721
- /**
722
- * Glyphs for the drawing tools and for host chrome, as path data.
723
- *
724
- * The engine ships no DOM, and this does not change that: an icon here is a
725
- * string of SVG path commands, not an element. The host still builds its own
726
- * toolbar, flyouts and rail; what it no longer has to do is draw every glyph
727
- * before it can show them. `icon-svg.ts` turns these into markup strings for a
728
- * host that wants the convenience; this file is the single source both of them
729
- * and every other surface read from.
730
- *
731
- * That was the real cost of leaving them out. Every adopter drew their own set,
732
- * each drifted on stroke weight, grid and visual density independently, and the
733
- * result read as sixty icons rather than as one set, however carefully any
734
- * single glyph was made. A shipped set is worth more than a better glyph.
735
- *
736
- * # Two tiers, one weight
737
- *
738
- * Tool glyphs live on a 24-unit grid and are shown at 24px in the rail. Host
739
- * chrome (undo, close, the settings tab rail) is shown at 16px beside them, and
740
- * a 24-grid glyph scaled to 16 lands its 2-unit stroke on 1.33 pixels, blurred
741
- * across two rows on every edge. So chrome has its own registry drawn on a
742
- * 16-unit grid with a 1.5 stroke. The two strokes are deliberately not in exact
743
- * proportion: a small glyph needs a slightly heavier relative stroke than a
744
- * large one to read as the same weight, and `tests/draw-icons.test.ts` holds
745
- * the chrome tier inside that band rather than at parity.
746
- *
747
- * # The grid
748
- *
749
- * Every glyph is authored to the same constraints, and `tests/draw-icons.test.ts`
750
- * enforces all of them mechanically, because a set of this size cannot be kept
751
- * consistent by review:
752
- *
753
- * - **One viewBox per tier.** 24 by 24 for tools, 16 by 16 for chrome, so a
754
- * host sets the size once per surface.
755
- * - **A margin all round.** Live area 2 to 22 on the tool grid, 1 to 15 on the
756
- * chrome grid. Without it, glyphs that happen to reach the edge look larger
757
- * than their neighbours and the rail reads as ragged.
758
- * - **Integer coordinates.** With `STROKE` of 2, an orthogonal edge centred on
759
- * an integer covers exactly two device pixels at 1:1, which is what makes it
760
- * crisp. Half-unit coordinates were the previous set's crispness bug: at a
761
- * 1.5 stroke on integers, nothing landed on a pixel boundary at any size.
762
- * - **One stroke weight per tier.** Three different weights across identically
763
- * sized boxes is the single most visible tell of a set assembled rather than
764
- * drawn.
765
- *
766
- * # Rendering
767
- *
768
- * Tool glyphs are crispest at 24px, and at any integer multiple of it. At 18px
769
- * the 0.75 scale puts a 2-unit stroke on 1.5 device pixels and every edge is
770
- * anti-aliased across two rows: that is a host sizing choice, not something the
771
- * path data can fix. Prefer 24, or 12 with a heavier weight. Chrome glyphs are
772
- * drawn for 16px and its multiples.
773
- */
774
- /** The viewBox every glyph is authored in. */
775
- declare const ICON_VIEWBOX = "0 0 24 24";
776
- /**
777
- * Stroke width in viewBox units. Paths carry no presentation attributes, so a
778
- * host that wants a lighter set overrides this once rather than editing glyphs.
779
- */
780
- declare const ICON_STROKE = 2;
781
- /**
782
- * The attribute bag a tier hands its host. Structural, so the markup builders
783
- * in `icon-svg.ts` take either tier's bag through one signature.
784
- */
785
- interface IconAttrs {
786
- readonly viewBox: string;
787
- readonly fill: 'none';
788
- readonly stroke: 'currentColor';
789
- readonly strokeWidth: number;
790
- readonly strokeLinecap: 'round';
791
- readonly strokeLinejoin: 'round';
792
- }
793
- /** Attributes a host should apply to the `<svg>`, so every set matches. */
794
- declare const ICON_ATTRS: {
795
- readonly viewBox: "0 0 24 24";
796
- readonly fill: "none";
797
- readonly stroke: "currentColor";
798
- readonly strokeWidth: 2;
799
- readonly strokeLinecap: "round";
800
- readonly strokeLinejoin: "round";
801
- };
802
- /**
803
- * Path data by tool id, plus a few keys a host toolbar needs that are not
804
- * themselves tools (`cursor`, the group headers).
805
- *
806
- * Values are the `d` attribute of one `<path>`. Multiple subpaths are joined
807
- * into the same string rather than split across elements, so a host renders one
808
- * node per glyph.
809
- */
810
- declare const DRAWING_TOOL_ICONS: Readonly<Record<string, string>>;
811
- /**
812
- * The glyph for a tool, or `undefined` when it has none.
813
- *
814
- * Undefined rather than a placeholder: a host that renders an empty box has a
815
- * visible gap to fix, while one handed a question mark ships it.
816
- */
817
- declare function drawingToolIcon(toolId: string): string | undefined;
818
- /** Every id this set covers, for a host building a palette from it. */
819
- declare function drawingToolIconIds(): string[];
820
- /** The viewBox every chrome glyph is authored in. */
821
- declare const CHROME_ICON_VIEWBOX = "0 0 16 16";
822
- /**
823
- * Chrome stroke width in viewBox units. Not the tool stroke scaled (that would
824
- * be 1.33): at 16px a glyph needs a touch more relative weight than at 24px to
825
- * read as the same line, and 1.5 is where the two rails match by eye.
826
- */
827
- declare const CHROME_ICON_STROKE = 1.5;
828
- /** Attributes a host should apply to the `<svg>` around a chrome glyph. */
829
- declare const CHROME_ICON_ATTRS: {
830
- readonly viewBox: "0 0 16 16";
831
- readonly fill: "none";
832
- readonly stroke: "currentColor";
833
- readonly strokeWidth: 1.5;
834
- readonly strokeLinecap: "round";
835
- readonly strokeLinejoin: "round";
836
- };
837
- /**
838
- * Path data for host chrome: the buttons around the chart rather than the
839
- * tools in it. Same rules as the tool tier (one path per glyph, no presentation
840
- * attributes, integer coordinates) on the 16 grid with a 1..15 live area.
841
- *
842
- * The pair `cursor` / `magnet` / `text` also exist in the tool registry, at 24.
843
- * They are drawn twice on purpose: a rail button and a toolbar button are
844
- * different sizes, and the whole point of a second grid is not scaling one
845
- * drawing to both.
846
- */
847
- declare const CHROME_ICONS: Readonly<Record<string, string>>;
848
- /**
849
- * Chrome glyphs meant to be painted solid. Paths carry no presentation
850
- * attributes, so the fill is applied by the wrapper (`chromeIconSvg` does it,
851
- * a host with its own wrapper reads this set) and the registry stays pure.
852
- */
853
- declare const CHROME_ICON_FILLED: ReadonlySet<string>;
854
- /** The chrome glyph for an id, or `undefined` when there is none. */
855
- declare function chromeIcon(id: string): string | undefined;
856
- /** Every id the chrome tier covers. */
857
- declare function chromeIconIds(): string[];
858
-
859
- /** Prefix of every `<symbol id>` in the sprite, and of every `<use href>`. */
860
- declare const ICON_SYMBOL_PREFIX = "oac-icon-";
861
- /** Options shared by the inline builders. */
862
- interface IconSvgOptions {
863
- /**
864
- * Width and height. A number is CSS pixels; a string is written verbatim, so
865
- * `'1em'` sizes the glyph with the surrounding text. Default: the grid's
866
- * native size (24 for tools, 16 for chrome), where the stroke is crispest.
867
- */
868
- size?: number | string;
869
- /** Stroke width in viewBox units. Default: the tier's `*_STROKE`. */
870
- stroke?: number;
871
- /** A class for the host's own styling. */
872
- className?: string;
873
- }
874
- /** Options for `toolCursor`. */
875
- interface ToolCursorOptions {
876
- /** Cursor image size in CSS pixels. Default 20. Browsers reject images over 128. */
877
- size?: number;
878
- /** The pointer's active pixel, from the image's top-left. Default: the centre. */
879
- hotspot?: readonly [number, number];
880
- /** Glyph colour. Default white. */
881
- color?: string;
882
- /**
883
- * Halo colour. Default: black under a light `color`, white under a dark one,
884
- * judged from a hex colour. A non-hex `color` gets a black halo unless this
885
- * is set.
886
- */
887
- halo?: string;
888
- /** The keyword after the image, for a browser that will not take it. Default `crosshair`. */
889
- fallback?: string;
890
- }
891
- /**
892
- * A complete inline `<svg>` for one tool glyph, stroked in `currentColor`.
893
- *
894
- * ```ts
895
- * button.innerHTML = iconSvg('trend-line');
896
- * button.innerHTML = iconSvg('trend-line', { size: '1em' });
897
- * ```
898
- */
899
- declare function iconSvg(id: string, opts?: IconSvgOptions): string;
900
- /**
901
- * A complete inline `<svg>` for one chrome glyph, on the 16 grid. Glyphs in
902
- * `CHROME_ICON_FILLED` are painted solid as well as stroked.
903
- */
904
- declare function chromeIconSvg(id: string, opts?: IconSvgOptions): string;
905
- /**
906
- * One hidden `<svg>` of `<symbol>`s, for a host that shows many glyphs and
907
- * wants each path in the document once. Inject it once, then place glyphs with
908
- * `iconUse`. Symbols carry the path and viewBox only; stroke and fill inherit
909
- * from the `<svg>` around each `<use>`, so one sprite serves every weight.
910
- *
911
- * Default: every tool glyph. Repeated ids collapse to one symbol, since a
912
- * duplicate element id is an invalid document.
913
- */
914
- declare function iconSprite(ids?: readonly string[]): string;
915
- /** An `<svg>` that references a symbol from `iconSprite`. Same frame as `iconSvg`. */
916
- declare function iconUse(id: string, opts?: IconSvgOptions): string;
917
- /**
918
- * A CSS `cursor` value carrying the tool's glyph, for the canvas while that
919
- * tool is armed.
920
- *
921
- * The glyph is drawn twice: once in `halo`, one pixel wider on each side, and
922
- * once in `color` on top, so it reads on a light chart and a dark one without
923
- * the host choosing per theme. The value is `url("data:image/svg+xml,...") x y,
924
- * fallback`, ready for `canvas.style.cursor`.
925
- */
926
- declare function toolCursor(id: string, opts?: ToolCursorOptions): string;
927
-
928
- /**
929
- * A `DrawingLayer` renders the drawings of one pane and answers the chart's
930
- * hit-test. Anchors live in `{ time, price }`, so the layer maps them through
931
- * the *fractional* index helpers: the gapless axis means an anchor can sit
932
- * between bars (inside a collapsed weekend) or past the last one (a forward
933
- * projection), and whole-index lookups have nothing to return there.
934
- *
935
- * Each pane carries **two** layers, one at z-order `bottom` for drawings with a
936
- * negative `zIndex` (under the series) and one at `top` for the rest. The top
937
- * one takes over handles and hit-testing for the pair through `setBelow`, so a
938
- * shape parked under the candles still shows its grab handles above them and
939
- * a click lands on whatever the eye sees on top.
940
- *
941
- * Hit ids are `draw:<id>` for the body and `draw:<id>#<n>` for anchor `n`, so
942
- * the controller can tell "move the whole shape" from "move this handle".
943
- *
944
- * The hover ring, the magnet ring and the hover handles are all overlay
945
- * state: they change on every pointer move, so they must only ever cost the
946
- * top canvas. The layer that paints them is the one whose `requestUpdate`
947
- * the chart maps to the cursor tier, which is why the bottom layer of a pair
948
- * stores that state and asks for nothing.
949
- */
950
-
951
- /** Which side of the series a layer paints on. */
952
- type DrawingLayerOrder = 'bottom' | 'top';
953
- /** The pointer kinds the layer sizes its targets for. */
954
- type DrawingPointerKind = 'mouse' | 'touch' | 'pen';
955
- /**
956
- * Paint order: by `zIndex`, ties by array position. `Array.prototype.sort` is
957
- * stable, which is what makes the tie rule hold without a second key.
958
- */
959
- declare function sortByZIndex(drawings: readonly Drawing[]): Drawing[];
960
- declare class DrawingLayer implements IPrimitive {
961
- private readonly _order;
962
- /** In paint order. */
963
- private _drawings;
964
- private _host;
965
- private _selected;
966
- /** The drawing under the pointer, whether or not it is selected. */
967
- private _hovered;
968
- /** Where the next click will land while the magnet is pulling it. */
969
- private _snap;
970
- /** Anchors of the in-progress drawing, plus the live cursor point. */
971
- private _preview;
972
- /** The layer under this one, whose handles and hits this layer answers for. */
973
- private _below;
974
- /** The layer that has taken over this one's handles and hit-testing. */
975
- private _above;
976
- /** Sizes grab targets for the device last seen. */
977
- private _touch;
978
- constructor(order?: DrawingLayerOrder);
979
- attached(host: PrimitiveHost): void;
980
- detached(): void;
981
- zOrder(): ZOrder;
982
- /** Drawings overlay the price range; they never drive it. */
983
- autoscaleInfo(): null;
984
- setDrawings(drawings: readonly Drawing[]): void;
985
- setSelected(ids: readonly string[]): void;
986
- /**
987
- * The drawing under the pointer. Its handles paint at a lighter weight than
988
- * a selection's, as the hint that it can be grabbed. Repaints only from the
989
- * layer that paints handles: the adopted bottom layer keeps the id for its
990
- * own bookkeeping and asks for nothing, since its repaint costs the series.
991
- */
992
- setHovered(id: string | null): void;
993
- hovered(): string | null;
994
- /**
995
- * The point the magnet will snap the next click to, or null when it is not
996
- * pulling. Painted as a hollow ring so the user sees the anchor land before
997
- * committing to it.
998
- */
999
- setSnapPoint(point: DrawingPoint | null): void;
1000
- snapPoint(): DrawingPoint | null;
1001
- /**
1002
- * Size the grab targets for the device in use. Touch doubles the radii; a
1003
- * mouse or a pen keeps the desktop sizes. The render context may carry the
1004
- * same fact (`pointerType`), and when it does that wins per call, so a
1005
- * first touch on a fresh chart is already sized right.
1006
- */
1007
- setPointerType(kind: DrawingPointerKind | null | undefined): void;
1008
- setPreview(drawing: Drawing | null): void;
1009
- /**
1010
- * Adopt the layer under this one. From then on this layer paints the handles
1011
- * of both and answers `hitTest` for both, and the adopted layer paints bodies
1012
- * only. Handles have to live up here: a selected drawing under the series
1013
- * would otherwise have its handles buried under the candles, and a handle
1014
- * you cannot see is a handle you cannot grab. Pass null to release.
1015
- */
1016
- setBelow(layer: DrawingLayer | null): void;
1017
- /** Repaint for overlay-only state, from the layer that paints it. */
1018
- private _requestOverlay;
1019
- /** Whether targets are sized for a fingertip on this call. */
1020
- private _isTouch;
1021
- private _grabRadius;
1022
- private _handleRadius;
1023
- /** Map an anchor to media px on this pane. */
1024
- private _project;
1025
- private _points;
1026
- /** Selected, unlocked drawings of this layer, in paint order. */
1027
- private _handled;
1028
- /**
1029
- * The hovered drawing of this layer, when it is one that could be grabbed
1030
- * and is not already showing selection handles.
1031
- */
1032
- private _hoverHandled;
1033
- draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
1034
- private _drawingContext;
1035
- private _drawContent;
1036
- private _drawPlacementGuide;
1037
- /**
1038
- * Anchor handles. A hover shows them light (thin, translucent) as a hint
1039
- * that the shape can be grabbed; a selection shows them at full weight.
1040
- */
1041
- private _drawHandles;
1042
- /** The magnet ring: hollow, in the axis text colour, at the snap point. */
1043
- private _drawSnapRing;
1044
- hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
1045
- private _hitHandle;
1046
- private _hitBody;
1047
- }
1048
-
1049
- /**
1050
- * Clipboard transfer for drawings: the layer between the drawing model and the
1051
- * OS clipboard.
1052
- *
1053
- * Two things make this more than `JSON.stringify`:
1054
- *
1055
- * 1. **The OS clipboard is shared with everything else on the machine.** A
1056
- * paste can arrive from a spreadsheet, another application, or a hand-edited
1057
- * copy of our own payload. So the payload is written under a namespaced key
1058
- * and everything read back is validated field by field before it can reach
1059
- * the model. Foreign text is *not ours* and is ignored, never an exception
1060
- * the host has to catch on every Ctrl+V.
1061
- * 2. **Clipboard access is async and permission-gated.** `navigator.clipboard`
1062
- * rejects when the document is not focused, the page is not secure, or the
1063
- * user denied the permission. Copy must still work inside the tab, so every
1064
- * write also lands in a module-level in-memory clipboard which is shared by
1065
- * every controller in the page. That is what makes chart-to-chart paste work
1066
- * with the permission denied, and it is why the memory store is a singleton
1067
- * rather than per-controller state.
1068
- *
1069
- * The payload body is a drawings document (`DrawingsDocument`), so a copy made
1070
- * by a 1.9.x build (a version 1 body carrying the old style-bag text fields)
1071
- * is upgraded by the same migration a saved layout goes through.
1072
- */
1073
-
1074
- /**
1075
- * Top-level key of the JSON payload. Namespaced so a paste of arbitrary text,
1076
- * or of JSON belonging to some other application, is recognisable as not ours
1077
- * by looking at one property.
1078
- */
1079
- declare const DRAWING_CLIPBOARD_KEY = "openalgo-charts/drawings";
1080
- /**
1081
- * Payload format version. Tracks the model version, since the body *is* a
1082
- * drawings document: version 1 carried 1.9.x drawings, version 2 carries the
1083
- * split text and levelled fibs.
1084
- */
1085
- declare const DRAWING_CLIPBOARD_VERSION: number;
1086
- /** The async slice of `navigator.clipboard` this module uses. */
1087
- interface ClipboardPort {
1088
- writeText(text: string): Promise<void>;
1089
- readText(): Promise<string>;
1090
- }
1091
- /** Test seam: drop whatever the in-memory clipboard is holding. */
1092
- declare function clearMemoryClipboard(): void;
1093
- /** `navigator.clipboard` when the browser exposes it, else null. */
1094
- declare function systemClipboard(): ClipboardPort | null;
1095
- /** Deep copy of the persisted fields, so a clone shares nothing with its source. */
1096
- declare function cloneDrawing(d: Drawing): Drawing;
1097
- /** Serialise drawings into the namespaced payload written to the clipboard. */
1098
- declare function encodeClipboardPayload(drawings: readonly Drawing[]): string;
1099
- /**
1100
- * Validate one entry into a drawing with no id. Returns null for anything that
1101
- * cannot be rendered: an unknown tool would throw inside the controller, and a
1102
- * NaN anchor produces a drawing that can never be drawn or hit-tested again.
1103
- * Accepts the 1.9.x shape too, lifting its text fields into `text`.
1104
- */
1105
- declare function sanitizeDrawing(value: unknown): Omit<Drawing, 'id'> | null;
1106
- /**
1107
- * Parse clipboard text into drawings, or null when the text is not ours or is
1108
- * not usable. All-or-nothing on purpose: a payload with one corrupt entry is a
1109
- * corrupt payload, and pasting the other nine silently would be worse than
1110
- * pasting none.
1111
- */
1112
- declare function decodeClipboardPayload(text: unknown): Omit<Drawing, 'id'>[] | null;
1113
- interface DrawingClipboardOptions {
1114
- /** Where to read and write. Defaults to `navigator.clipboard` when present. */
1115
- port?: ClipboardPort | null;
1116
- /**
1117
- * Keep a copy in the shared in-memory clipboard so copy and paste keep
1118
- * working when the OS clipboard is unavailable or the permission is refused.
1119
- * Default true. Set false to make a failed system write a failed copy, which
1120
- * a host that must not silently lose cross-tab transfer may prefer.
1121
- */
1122
- fallbackToMemory?: boolean;
1123
- }
1124
- /**
1125
- * The clipboard as the controller sees it: drawings in, drawings out, no
1126
- * exceptions escaping. Every failure mode (no clipboard API, refused
1127
- * permission, foreign text, corrupt payload) reduces to `false` or `null`.
1128
- */
1129
- declare class DrawingClipboard {
1130
- private _port;
1131
- private _fallback;
1132
- /** Why the last operation did not reach the OS clipboard, if it did not. */
1133
- private _lastError;
1134
- constructor(options?: DrawingClipboardOptions);
1135
- /** Swap the port at runtime (a host granting permission later, or a test). */
1136
- setPort(port: ClipboardPort | null): void;
1137
- /**
1138
- * Turn the in-memory backstop off or on. With it off, a refused system write
1139
- * is a failed copy, which is what a host wants when a cut that cannot reach
1140
- * the OS clipboard must not delete the drawing.
1141
- */
1142
- setFallbackToMemory(enabled: boolean): void;
1143
- /**
1144
- * Why the OS clipboard was not used by the last call, or null when it was.
1145
- * Set on a successful copy too, when the payload reached memory but not the
1146
- * system clipboard: that copy works in this tab and will not appear in
1147
- * another, which is exactly what a host wants to be able to tell the user.
1148
- */
1149
- lastError(): string | null;
1150
- /**
1151
- * Write drawings out. Resolves true when the payload is retrievable by a
1152
- * later `read()` (through the system clipboard, or through memory when the
1153
- * fallback is on), false when it is not, so a caller doing a cut knows
1154
- * whether it is safe to delete the original.
1155
- */
1156
- write(drawings: readonly Drawing[]): Promise<boolean>;
1157
- /**
1158
- * Read drawings back, or null when there is nothing of ours to paste. The
1159
- * system clipboard wins when it holds our payload, so a copy made in another
1160
- * tab beats a stale in-tab one; memory is consulted when the read fails or
1161
- * returns something that is not ours. That last case can paste an older copy
1162
- * after the user has copied unrelated text elsewhere, which is the deliberate
1163
- * trade: losing the copy whenever a browser refuses the read half of the
1164
- * permission would be the worse surprise.
1165
- */
1166
- read(): Promise<Omit<Drawing, 'id'>[] | null>;
1167
- }
1168
-
1169
- /**
1170
- * Drawing controller: the interaction and persistence layer over
1171
- * `DrawingLayer`. It is **headless**: no DOM, no toolbar. A host sets the
1172
- * active tool (from its own button, a shortcut, a command palette) and the
1173
- * controller runs placement, selection, dragging, undo, and serialisation.
1174
- *
1175
- * It listens on the chart's event bus (`click`, `crosshair:move`, `drag`,
1176
- * `drag:end`) rather than the single-slot `subscribeClick`/`subscribeDrag`
1177
- * callbacks, so a host keeps using those for its own order lines.
1178
- *
1179
- * Selection is a list. Every method that edits takes the whole list into one
1180
- * undo entry, so a multi-drag, a batch delete or a paste of ten shapes is one
1181
- * Ctrl+Z, which is what the hand that did it expects.
1182
- */
1183
-
1184
- /**
1185
- * The slice of the chart this controller needs.
1186
- *
1187
- * Declared structurally rather than as `Chart` on purpose. Each tier ships its
1188
- * own bundled `.d.ts`, so naming the class here made the draw tier re-declare
1189
- * `Chart`, and because `Chart` has private members, TypeScript treats the two
1190
- * declarations as *different* types. A TS consumer passing the chart from
1191
- * `createChart()` got "separate declarations of a private property", which made
1192
- * the tier unusable from TypeScript at all. An interface with no private
1193
- * members is structural, so the real `Chart` satisfies it with nothing to cast.
634
+ * Declared structurally rather than as `Chart` on purpose. Each tier ships its
635
+ * own bundled `.d.ts`, so naming the class here made the draw tier re-declare
636
+ * `Chart`, and because `Chart` has private members, TypeScript treats the two
637
+ * declarations as *different* types. A TS consumer passing the chart from
638
+ * `createChart()` got "separate declarations of a private property", which made
639
+ * the tier unusable from TypeScript at all. An interface with no private
640
+ * members is structural, so the real `Chart` satisfies it with nothing to cast.
1194
641
  */
1195
642
  interface DrawingChartHost {
643
+ readonly isDestroyed?: boolean;
1196
644
  /**
1197
645
  * The event bus. The controller listens for `click`, `crosshair:move`,
1198
646
  * `drag`, `drag:end` and `dblclick`, and for `hover` (`{ id }`, the hit id
@@ -1279,13 +727,15 @@ interface DrawingControllerOptions {
1279
727
  pasteOffsetPixels?: number;
1280
728
  }
1281
729
  /** What `drawing:change` reports happened to the listed ids. */
1282
- type DrawingChangeKind = 'add' | 'update' | 'remove' | 'reorder';
730
+ type DrawingChangeKind = 'add' | 'update' | 'remove' | 'reorder' | 'undo' | 'redo';
1283
731
  declare class DrawingController {
1284
732
  private readonly _chart;
1285
733
  private _opts;
1286
734
  private readonly _clipboard;
1287
735
  private readonly _layers;
1288
736
  private _drawings;
737
+ private readonly _linkedPreviews;
738
+ private _destroyed;
1289
739
  private _tool;
1290
740
  private _pending;
1291
741
  private _pendingPane;
@@ -1307,6 +757,7 @@ declare class DrawingController {
1307
757
  /** Snapshots for undo/redo; each is a full drawing list (they are small). */
1308
758
  private _undo;
1309
759
  private _redo;
760
+ private _pendingHistory;
1310
761
  /**
1311
762
  * One gesture's starting state. `items` are ids rather than objects because
1312
763
  * an undo mid-drag replaces every drawing object, and a stale reference
@@ -1348,6 +799,13 @@ declare class DrawingController {
1348
799
  */
1349
800
  drawings(): readonly Drawing[];
1350
801
  get(id: string): Drawing | undefined;
802
+ get isDestroyed(): boolean;
803
+ /** Apply a linked commit without adding to this chart's local undo history. */
804
+ applyLinkedDrawing(id: string, drawing: Drawing | null): void;
805
+ /** A linked drag paints over its committed drawing without changing saved state. */
806
+ setLinkedPreview(id: string, drawing: Drawing | null): void;
807
+ /** Reorder related drawings inside their existing slots, preserving unrelated local order. */
808
+ reorderLinkedDrawings(ids: readonly string[]): void;
1351
809
  /** Supported numeric levels, independent of whether the queried time lies on the shape. */
1352
810
  alertInfo(id: string): AlertDrawingInfo;
1353
811
  /** Numeric drawing value using the actual pane projection and collapsed time axis. */
@@ -1457,6 +915,7 @@ declare class DrawingController {
1457
915
  private _offsetTime;
1458
916
  undo(): boolean;
1459
917
  redo(): boolean;
918
+ private _applyHistory;
1460
919
  /** Drop selected ids the model no longer holds, after a history jump. */
1461
920
  private _pruneSelection;
1462
921
  canUndo(): boolean;
@@ -1546,78 +1005,753 @@ declare class DrawingController {
1546
1005
  private _onClick;
1547
1006
  private _placePoint;
1548
1007
  /**
1549
- * Where a click at `point` actually lands for the armed tool: on the 45
1550
- * degree lock while Shift holds the free end of a line, else on the magnet
1551
- * when it pulls, else where it was. The lock wins over the magnet because a
1552
- * snapped price would bend the exact angle the lock exists to give.
1008
+ * Where a click at `point` actually lands for the armed tool: on the 45
1009
+ * degree lock while Shift holds the free end of a line, else on the magnet
1010
+ * when it pulls, else where it was. The lock wins over the magnet because a
1011
+ * snapped price would bend the exact angle the lock exists to give.
1012
+ */
1013
+ private _aimPoint;
1014
+ /**
1015
+ * The free end of a two-anchor line under angle lock, or null when the lock
1016
+ * does not apply: no Shift, a tool without the flag, no anchor yet to
1017
+ * measure from, or a host that cannot map pixels (the lock is a screen
1018
+ * angle, so there is nothing to lock to in data space).
1019
+ */
1020
+ private _lockedPoint;
1021
+ /**
1022
+ * The nearest O/H/L/C of the hovered bar, at that bar's time, when the
1023
+ * magnet pulls; null when it does not. `strong` always pulls; `weak` only
1024
+ * within a few pixels, measured on screen so the pull is the same reach at
1025
+ * every zoom. Price panes only: an indicator pane's values are not prices.
1026
+ */
1027
+ private _snapPoint;
1028
+ private _onDrag;
1029
+ private _emitDragPreview;
1030
+ /** Roll back an interrupted drag and leave the pre-gesture undo/redo stacks intact. */
1031
+ cancelDrag(): boolean;
1032
+ /** Apply one drag frame to the model, from the gesture's snapshot. */
1033
+ private _moveDrag;
1034
+ /** How far down the screen `to` is from `from` on one pane, in media px. */
1035
+ private _pixelDelta;
1036
+ /** An anchor in container media px, or null on a host without the mapping. */
1037
+ private _toPixel;
1038
+ /** The inverse of `_toPixel`. */
1039
+ private _fromPixel;
1040
+ /**
1041
+ * `free` projected onto the nearest 45 degree ray from `anchor`, all in
1042
+ * screen space: the angle the eye reads is the one on the canvas, and a log
1043
+ * scale or a tall pane would make a data-space angle anything but. The
1044
+ * projection rather than a rotation, so a level line still ends under the
1045
+ * pointer's x and a vertical one under its y; only the stray axis is
1046
+ * dropped. Null when the host cannot map pixels, or the two coincide.
1047
+ */
1048
+ private _lockAngle;
1049
+ private _onDragEnd;
1050
+ /**
1051
+ * The pair of layers for a pane, made on first use. The bottom one is added
1052
+ * first so a host that lists primitives sees them in paint order; the top one
1053
+ * adopts it so handles and hit-tests come from one place.
1054
+ */
1055
+ private _layerFor;
1056
+ /** Whether a drawing paints on the top layer: over the series, or lifted for a drag. */
1057
+ private _onTop;
1058
+ /** Push the current list into each pane's layers and into the chart state. */
1059
+ private _sync;
1060
+ /**
1061
+ * The per-frame half of a drag: only the top layers of the panes the
1062
+ * gesture touches are re-listed, so the repaint stays on the cursor tier.
1063
+ * Everything moving is on a top layer by then (anything under the series
1064
+ * was lifted when the gesture began), and the bottom layers have not
1065
+ * changed since, so re-listing them would cost a series repaint for
1066
+ * nothing.
1067
+ */
1068
+ private _syncDrag;
1069
+ /**
1070
+ * Mirror the in-progress anchors (plus the cursor) into the preview slot.
1071
+ * The cursor point goes through the same aim as a click would, so the
1072
+ * preview shows the locked angle or the snapped anchor before it lands.
1073
+ */
1074
+ private _syncPreview;
1075
+ /**
1076
+ * Show where the magnet will land the next click, or nothing. A ring only
1077
+ * while a click would place an anchor: a tool armed, not a brush (which
1078
+ * inks where the pointer is), and the pull actually applying at the cursor.
1079
+ * Angle lock bypasses the magnet, so it hides the ring too.
1080
+ */
1081
+ private _syncSnapRing;
1082
+ private _pushUndo;
1083
+ }
1084
+
1085
+ /** Both fields must be known. A host may use its feed namespace as the exchange. */
1086
+ interface DrawingLinkContext {
1087
+ symbol?: string;
1088
+ exchange?: string;
1089
+ }
1090
+ /** Resolve a host-owned identity without modifying the chart's data context. */
1091
+ type DrawingLinkContextSource = DrawingLinkContext | (() => DrawingLinkContext | null | undefined);
1092
+ interface DrawingLinkOptions {
1093
+ enabled?: boolean;
1094
+ }
1095
+ interface DrawingLinkChart extends Pick<DrawingChartHost, 'on'> {
1096
+ readonly isDestroyed?: boolean;
1097
+ getDataContext?(): Readonly<DrawingLinkContext> | undefined;
1098
+ }
1099
+ /**
1100
+ * Existing local drawings stay local until `share` is called. Persisted shared
1101
+ * lineage reconnects across restores. Only price-pane drawings participate; time anchors
1102
+ * cross the boundary unchanged so each interval uses its own coordinate map.
1103
+ */
1104
+ declare class DrawingLinkGroup {
1105
+ private readonly _members;
1106
+ private _enabled;
1107
+ private _broadcasting;
1108
+ private _destroyed;
1109
+ constructor(options?: DrawingLinkOptions);
1110
+ options(): Required<DrawingLinkOptions>;
1111
+ add(chart: DrawingLinkChart, controller: DrawingController, context?: DrawingLinkContextSource): void;
1112
+ setOptions(options: DrawingLinkOptions): void;
1113
+ /** Report the current instrument. Unknown identity stops sharing immediately. */
1114
+ setContext(chart: DrawingLinkChart, context: DrawingLinkContext | undefined): void;
1115
+ /** Share selected ids, or every existing eligible drawing when ids are omitted. */
1116
+ share(chart: DrawingLinkChart, ids?: readonly string[]): number;
1117
+ has(chart: DrawingLinkChart): boolean;
1118
+ /** Committed drawings remain on peers; transient previews are discarded. */
1119
+ remove(chart: DrawingLinkChart): void;
1120
+ destroy(): void;
1121
+ private _eligible;
1122
+ private _create;
1123
+ private _reconnect;
1124
+ private _change;
1125
+ private _commit;
1126
+ private _preview;
1127
+ private _syncOrder;
1128
+ private _orderFrom;
1129
+ private _clearPreview;
1130
+ private _clearMemberPreviews;
1131
+ private _detachDrawings;
1132
+ }
1133
+ declare function createDrawingLinkGroup(options?: DrawingLinkOptions): DrawingLinkGroup;
1134
+
1135
+ /**
1136
+ * Built-in drawing tools + the tool registry. Same philosophy as the chart-type
1137
+ * and indicator registries: a tool is a descriptor, the layer just runs it, and
1138
+ * `registerDrawingTool` makes a custom one first-class.
1139
+ *
1140
+ * `draw` receives anchors already in device px; `distance` receives them in
1141
+ * media px, the same space as the incoming cursor.
1142
+ *
1143
+ * Text lives in `drawing.text` (a `DrawingText`), never in the style bag: a
1144
+ * shape's outline colour and its label colour are two decisions, and a tool
1145
+ * that prints only a readout (a fib ladder, a measure chip) still reads its
1146
+ * face from there. Ladders read `FibLevel[]` and stroke each level in its own
1147
+ * colour, taken from the shared palette in levels.ts.
1148
+ *
1149
+ * Every tool declares `settings`: the fields a host may show for it. The
1150
+ * schema is a contract, not a wish list. A field is declared only when this
1151
+ * file reads it, because a control with nothing behind it is a defect.
1152
+ */
1153
+
1154
+ declare function registerDrawingTool(tool: DrawingTool): void;
1155
+ declare function getDrawingTool(id: string): DrawingTool;
1156
+ declare function hasDrawingTool(id: string): boolean;
1157
+ declare function registeredDrawingTools(): DrawingTool[];
1158
+ /** Keyboard event fields a shortcut is matched against. */
1159
+ interface ShortcutEvent {
1160
+ key: string;
1161
+ altKey?: boolean;
1162
+ ctrlKey?: boolean;
1163
+ metaKey?: boolean;
1164
+ shiftKey?: boolean;
1165
+ }
1166
+ /**
1167
+ * The id of the tool whose `shortcut` matches this key event, or `null`.
1168
+ *
1169
+ * Pure, so a host can bind one `keydown` listener and decide for itself when
1170
+ * shortcuts apply. The library installs no listener, because only the host
1171
+ * knows whether the chart has focus, a dialog is open, or the user is typing.
1172
+ *
1173
+ * Modifiers must match exactly: `Alt+T` will not fire for `Ctrl+Alt+T`, so a
1174
+ * tool shortcut cannot shadow a browser or host chord. `metaKey` (Cmd) is
1175
+ * treated as Ctrl, which is what a Mac user expects.
1176
+ */
1177
+ declare function matchDrawingShortcut(e: ShortcutEvent): string | null;
1178
+ /** Every registered tool that has a shortcut, as `id -> shortcut`. */
1179
+ declare function drawingShortcuts(): Record<string, string>;
1180
+ /**
1181
+ * The settings a host may show for a tool: the tool's own declaration, else
1182
+ * the line fields, which every stroked custom tool reads. This is a registry
1183
+ * lookup, which is why it lives here and not in schema.ts: that module stays
1184
+ * free of any import that could loop back into this one.
1185
+ */
1186
+ declare function drawingSettingsSchema(toolId: string): SettingsSchema;
1187
+ declare const TREND_LINE: DrawingTool;
1188
+ declare const RAY: DrawingTool;
1189
+ declare const EXTENDED_LINE: DrawingTool;
1190
+ declare const ARROW: DrawingTool;
1191
+ declare const HORIZONTAL_LINE: DrawingTool;
1192
+ declare const HORIZONTAL_RAY: DrawingTool;
1193
+ declare const VERTICAL_LINE: DrawingTool;
1194
+ declare const CROSS_LINE: DrawingTool;
1195
+ declare const RECTANGLE: DrawingTool;
1196
+ declare const ELLIPSE: DrawingTool;
1197
+ declare const PARALLEL_CHANNEL: DrawingTool;
1198
+ declare const FIB_RETRACEMENT: DrawingTool;
1199
+ declare const FIB_EXTENSION: DrawingTool;
1200
+ declare const MEASURE: DrawingTool;
1201
+ declare const LONG_POSITION: DrawingTool;
1202
+ declare const SHORT_POSITION: DrawingTool;
1203
+ declare const TEXT: DrawingTool;
1204
+ /**
1205
+ * Path: click each vertex, double-click to finish, arrowhead on the last leg.
1206
+ * The arrow is what separates it from `polyline`: a path points somewhere.
1207
+ */
1208
+ declare const PATH: DrawingTool;
1209
+ /**
1210
+ * Brush: freehand ink. Press, drag, release. The anchors are the thinned
1211
+ * samples of the gesture and the spline between them is what is stroked, so
1212
+ * the ink stays a curve after the thinning that keeps a stroke small.
1213
+ */
1214
+ declare const BRUSH: DrawingTool;
1215
+ /**
1216
+ * Rotated rectangle: anchors 0 and 1 lay out one edge (and so the rotation),
1217
+ * and anchor 2 sets the depth perpendicular to it. An axis-aligned `rectangle`
1218
+ * cannot follow a trend channel; this can.
1219
+ */
1220
+ declare const ROTATED_RECTANGLE: DrawingTool;
1221
+ /**
1222
+ * Double curve: an S through three anchors. `curve` bends one way off a single
1223
+ * control; this mirrors that control about the midpoint so the second half bends
1224
+ * back, which is the shape a rounded top-then-bottom actually needs.
1225
+ */
1226
+ declare const DOUBLE_CURVE: DrawingTool;
1227
+ /**
1228
+ * Cyclic lines: vertical lines repeating at the interval the two anchors set,
1229
+ * for reading a rhythm forward off a measured swing.
1230
+ */
1231
+ declare const CYCLIC_LINES: DrawingTool;
1232
+ /**
1233
+ * Time cycles: semicircles of the anchors' width repeating along the axis, the
1234
+ * classic cycle-projection overlay.
1235
+ */
1236
+ declare const TIME_CYCLES: DrawingTool;
1237
+ /**
1238
+ * Sine line: a full wave between the anchors. The horizontal span is one
1239
+ * period, the vertical offset its amplitude.
1240
+ */
1241
+ declare const SINE_LINE: DrawingTool;
1242
+ /**
1243
+ * Price label: a pill of the anchored price with a tail pointing at the bar.
1244
+ * Reads its value off the anchor, so dragging it re-reads rather than going
1245
+ * stale the way a typed-in text would. Text, when given, replaces the price.
1246
+ */
1247
+ declare const PRICE_LABEL: DrawingTool;
1248
+ /**
1249
+ * Callout: a text bubble on its own anchor with a tail back to the point it
1250
+ * annotates, so the note can sit clear of the price action it refers to.
1251
+ */
1252
+ declare const CALLOUT: DrawingTool;
1253
+ /** Flag mark: a pennant on a pole at one anchor, for tagging a bar. */
1254
+ declare const FLAG_MARK: DrawingTool;
1255
+ /**
1256
+ * Note: a pin at the bar with its text to the upper right.
1257
+ *
1258
+ * The pin is the point being annotated and the plate is the annotation, which
1259
+ * is why the two are drawn as separate marks joined by a stem rather than as
1260
+ * one bubble: the reader needs to see exactly which bar is meant, and a bubble
1261
+ * wide enough to hold a sentence covers several.
1262
+ */
1263
+ declare const NOTE: DrawingTool;
1264
+ /**
1265
+ * Balloon: a speech bubble sitting above its anchor, tail pointing down.
1266
+ *
1267
+ * One anchor rather than the callout's two: a balloon is for saying something
1268
+ * *about this bar*, so letting the bubble be dragged away from what it labels
1269
+ * would only invite it to drift.
1270
+ */
1271
+ declare const BALLOON: DrawingTool;
1272
+ /**
1273
+ * Comment: a small square-cornered box with a tail off its bottom left.
1274
+ *
1275
+ * Deliberately plainer than the balloon: a chart that says something at every
1276
+ * other bar needs one of these marks to be quiet, and the shape is the only
1277
+ * thing distinguishing them once both are the user's own colour.
1278
+ */
1279
+ declare const COMMENT: DrawingTool;
1280
+ /**
1281
+ * Signpost: a post standing on the bar with its plate at the top.
1282
+ *
1283
+ * The one annotation anchored to *time* rather than to a level: the post is
1284
+ * vertical so the plate can clear the price action entirely while the foot
1285
+ * still names an exact bar. Useful for events, which happen at a moment and
1286
+ * not at a price.
1287
+ */
1288
+ declare const SIGNPOST: DrawingTool;
1289
+ /**
1290
+ * Price note: the anchored price, with the user's text under it.
1291
+ *
1292
+ * The price is read off the anchor rather than typed, so dragging the note
1293
+ * re-reads it. A typed price is a number that was true once, which on a chart
1294
+ * is worse than no number at all.
1295
+ */
1296
+ declare const PRICE_NOTE: DrawingTool;
1297
+ /**
1298
+ * Table: rows of text in a grid, anchored top-left.
1299
+ *
1300
+ * Cells come from the text: a newline starts a row and a pipe separates
1301
+ * columns, so a whole table is one editable string and survives `getState`
1302
+ * with no new shape in the drawing model. The first row is drawn as a header
1303
+ * because a table on a chart is nearly always labelled.
1304
+ */
1305
+ declare const TABLE: DrawingTool;
1306
+ /**
1307
+ * Measurers. `measure` reports price *and* time together; these two constrain it
1308
+ * to one axis, which is what you want when the other one is noise: sizing a
1309
+ * retracement without caring how long it took, or counting bars to an event
1310
+ * without caring where price went.
1311
+ */
1312
+ declare const PRICE_RANGE: DrawingTool;
1313
+ declare const DATE_RANGE: DrawingTool;
1314
+ /**
1315
+ * Position forecast: project a move from an anchor. Two anchors give the
1316
+ * projected leg; the shape extends the same slope past the target as a dashed
1317
+ * cone, so the drawing says "if this continues" rather than just marking a line.
1318
+ */
1319
+ declare const FORECAST: DrawingTool;
1320
+ /**
1321
+ * Circle from centre + a radius handle. The radius is measured in *pixels*, so
1322
+ * it stays a circle on screen instead of the ellipse the two axes' differing
1323
+ * scales would otherwise produce.
1324
+ */
1325
+ declare const CIRCLE: DrawingTool;
1326
+ declare const TRIANGLE: DrawingTool;
1327
+ /** Free-form polyline: click each vertex, double-click to finish. */
1328
+ declare const POLYLINE: DrawingTool;
1329
+ /** Arc through three anchors: the middle one is on the curve, not a handle. */
1330
+ declare const ARC: DrawingTool;
1331
+ /** Quadratic curve: the middle anchor is a control handle, off the curve. */
1332
+ declare const CURVE: DrawingTool;
1333
+ declare const ARROW_UP: DrawingTool;
1334
+ declare const ARROW_DOWN: DrawingTool;
1335
+ declare const ARROW_LEFT: DrawingTool;
1336
+ declare const ARROW_RIGHT: DrawingTool;
1337
+ /** Highlighter: the brush with a fat, translucent stroke. */
1338
+ declare const HIGHLIGHTER: DrawingTool;
1339
+ /** Fib channel: fib levels spread across a trend leg, parallel to it. */
1340
+ declare const FIB_CHANNEL: DrawingTool;
1341
+ /**
1342
+ * Fib time zone: vertical lines at Fibonacci multiples of the base leg's width.
1343
+ * Its levels count bars rather than divide a leg, so they carry no convention
1344
+ * colour and fall back to the drawing's own.
1345
+ */
1346
+ declare const FIB_TIME_ZONE: DrawingTool;
1347
+ /** Rays from the anchor at fib fractions of the leg: the speed resistance fan. */
1348
+ declare const FIB_FAN: DrawingTool;
1349
+ /**
1350
+ * Gann fan: rays from one anchor at the classic price/time angles. A level's
1351
+ * ratio is price per unit of time, so the 1x1 is 1, the 1x2 is 0.5 and the
1352
+ * 2x1 is 2; each angle keeps its own colour from the cycle palette.
1353
+ */
1354
+ declare const GANN_FAN: DrawingTool;
1355
+ /**
1356
+ * Gann box: the drawn rectangle divided at its levels on both axes, plus the
1357
+ * 1x1 diagonal. Ratio 0 is the first anchor's price and time, ratio 1 the
1358
+ * second's, so the box reads like a retracement laid over a date range.
1359
+ */
1360
+ declare const GANN_BOX: DrawingTool;
1361
+ declare const BUILTIN_DRAWING_TOOLS: readonly DrawingTool[];
1362
+ /** Register every built-in tool. Idempotent; called on tier import. */
1363
+ declare function registerBuiltinDrawingTools(): void;
1364
+
1365
+ /**
1366
+ * The shared level palette for the Fibonacci and Gann family.
1367
+ *
1368
+ * Every ladder tool (retracement, extension, channel, fan, time zone, the Gann
1369
+ * fan and box) strokes a list of ratios, and each ratio has a colour the eye
1370
+ * expects: 0.618 reads as one thing across every tool, not a different hue per
1371
+ * tool. Before this module each tool would have restated those colours, and
1372
+ * restated colours drift. This is the one statement; tools take their defaults
1373
+ * from it and hosts seed a newly added level from it.
1374
+ *
1375
+ * Pure: no DOM, no registry. Safe to import from a worker or a settings panel.
1376
+ */
1377
+
1378
+ /**
1379
+ * The colour of a ratio that is an anchor rather than a level (0, 1, 2, 3 are
1380
+ * where the measured leg starts and ends, or whole multiples of it) and of any
1381
+ * ratio the convention does not name. Neutral on purpose: it is the reference
1382
+ * the coloured levels are read against.
1383
+ */
1384
+ declare const LEVEL_NEUTRAL = "#787b86";
1385
+ /**
1386
+ * The conventional colour for a Fibonacci ratio. Anchors (0, 1, 2, 3) and any
1387
+ * ratio without a convention come back {@link LEVEL_NEUTRAL}, so a host can call
1388
+ * this for every new level and always get a usable colour.
1389
+ */
1390
+ declare function levelColor(ratio: number): string;
1391
+ /**
1392
+ * A short sequence of colours that stay distinguishable side by side, for
1393
+ * tools whose levels are positions rather than ratios: the angles of a Gann
1394
+ * fan, the repeats of a cycle. Index `i` wraps, so any count is safe.
1395
+ */
1396
+ declare const CYCLE_PALETTE: readonly string[];
1397
+ /** The `i`th cycle colour. Wraps in both directions; a negative index is fine. */
1398
+ declare function cycleColor(i: number): string;
1399
+ /** `0.618` as `61.8%`: the text a level prints when it carries no label. */
1400
+ declare function formatRatio(ratio: number): string;
1401
+ /**
1402
+ * The label for a Gann angle stored as a price-per-time ratio: `1` is the 1x1,
1403
+ * `0.5` the 1x2, `2` the 2x1. Ratios that are not clean reciprocals fall back
1404
+ * to the ratio itself, which is still true, just less idiomatic.
1405
+ */
1406
+ declare function gannLabel(ratio: number): string;
1407
+ /** A mutable copy of a default ladder, for a fresh drawing's own `style.levels`. */
1408
+ declare function cloneLevels(levels: readonly FibLevel[]): FibLevel[];
1409
+ /** Retracement and extension: the classic ladder, coloured by convention. */
1410
+ declare const DEFAULT_FIB: readonly FibLevel[];
1411
+ /** Speed fan: rays at the fractions of the leg. No 0 ray, it would be flat. */
1412
+ declare const DEFAULT_FIB_FAN: readonly FibLevel[];
1413
+ /** Gann box: quarters plus the golden pair, applied to both axes of the box. */
1414
+ declare const DEFAULT_GANN_BOX: readonly FibLevel[];
1415
+ /**
1416
+ * Gann fan: the classic angles as price-per-time ratios, 1x8 up to 8x1. These
1417
+ * are positions in a sequence rather than Fibonacci ratios, so they take the
1418
+ * cycle palette.
1419
+ */
1420
+ declare const DEFAULT_GANN_FAN: readonly FibLevel[];
1421
+ /**
1422
+ * Time zones count bars along the Fibonacci sequence, so `ratio` here is a
1423
+ * multiple of the anchor leg, not a fraction of it. No colour is set: there is
1424
+ * no convention for "the 13 line", so every zone takes the drawing's own colour
1425
+ * until the user gives one its own.
1426
+ */
1427
+ declare const DEFAULT_FIB_TIME_ZONE: readonly FibLevel[];
1428
+
1429
+ /**
1430
+ * Glyphs for the drawing tools and for host chrome, as path data.
1431
+ *
1432
+ * The engine ships no DOM, and this does not change that: an icon here is a
1433
+ * string of SVG path commands, not an element. The host still builds its own
1434
+ * toolbar, flyouts and rail; what it no longer has to do is draw every glyph
1435
+ * before it can show them. `icon-svg.ts` turns these into markup strings for a
1436
+ * host that wants the convenience; this file is the single source both of them
1437
+ * and every other surface read from.
1438
+ *
1439
+ * That was the real cost of leaving them out. Every adopter drew their own set,
1440
+ * each drifted on stroke weight, grid and visual density independently, and the
1441
+ * result read as sixty icons rather than as one set, however carefully any
1442
+ * single glyph was made. A shipped set is worth more than a better glyph.
1443
+ *
1444
+ * # Two tiers, one weight
1445
+ *
1446
+ * Tool glyphs live on a 24-unit grid and are shown at 24px in the rail. Host
1447
+ * chrome (undo, close, the settings tab rail) is shown at 16px beside them, and
1448
+ * a 24-grid glyph scaled to 16 lands its 2-unit stroke on 1.33 pixels, blurred
1449
+ * across two rows on every edge. So chrome has its own registry drawn on a
1450
+ * 16-unit grid with a 1.5 stroke. The two strokes are deliberately not in exact
1451
+ * proportion: a small glyph needs a slightly heavier relative stroke than a
1452
+ * large one to read as the same weight, and `tests/draw-icons.test.ts` holds
1453
+ * the chrome tier inside that band rather than at parity.
1454
+ *
1455
+ * # The grid
1456
+ *
1457
+ * Every glyph is authored to the same constraints, and `tests/draw-icons.test.ts`
1458
+ * enforces all of them mechanically, because a set of this size cannot be kept
1459
+ * consistent by review:
1460
+ *
1461
+ * - **One viewBox per tier.** 24 by 24 for tools, 16 by 16 for chrome, so a
1462
+ * host sets the size once per surface.
1463
+ * - **A margin all round.** Live area 2 to 22 on the tool grid, 1 to 15 on the
1464
+ * chrome grid. Without it, glyphs that happen to reach the edge look larger
1465
+ * than their neighbours and the rail reads as ragged.
1466
+ * - **Integer coordinates.** With `STROKE` of 2, an orthogonal edge centred on
1467
+ * an integer covers exactly two device pixels at 1:1, which is what makes it
1468
+ * crisp. Half-unit coordinates were the previous set's crispness bug: at a
1469
+ * 1.5 stroke on integers, nothing landed on a pixel boundary at any size.
1470
+ * - **One stroke weight per tier.** Three different weights across identically
1471
+ * sized boxes is the single most visible tell of a set assembled rather than
1472
+ * drawn.
1473
+ *
1474
+ * # Rendering
1475
+ *
1476
+ * Tool glyphs are crispest at 24px, and at any integer multiple of it. At 18px
1477
+ * the 0.75 scale puts a 2-unit stroke on 1.5 device pixels and every edge is
1478
+ * anti-aliased across two rows: that is a host sizing choice, not something the
1479
+ * path data can fix. Prefer 24, or 12 with a heavier weight. Chrome glyphs are
1480
+ * drawn for 16px and its multiples.
1481
+ */
1482
+ /** The viewBox every glyph is authored in. */
1483
+ declare const ICON_VIEWBOX = "0 0 24 24";
1484
+ /**
1485
+ * Stroke width in viewBox units. Paths carry no presentation attributes, so a
1486
+ * host that wants a lighter set overrides this once rather than editing glyphs.
1487
+ */
1488
+ declare const ICON_STROKE = 2;
1489
+ /**
1490
+ * The attribute bag a tier hands its host. Structural, so the markup builders
1491
+ * in `icon-svg.ts` take either tier's bag through one signature.
1492
+ */
1493
+ interface IconAttrs {
1494
+ readonly viewBox: string;
1495
+ readonly fill: 'none';
1496
+ readonly stroke: 'currentColor';
1497
+ readonly strokeWidth: number;
1498
+ readonly strokeLinecap: 'round';
1499
+ readonly strokeLinejoin: 'round';
1500
+ }
1501
+ /** Attributes a host should apply to the `<svg>`, so every set matches. */
1502
+ declare const ICON_ATTRS: {
1503
+ readonly viewBox: "0 0 24 24";
1504
+ readonly fill: "none";
1505
+ readonly stroke: "currentColor";
1506
+ readonly strokeWidth: 2;
1507
+ readonly strokeLinecap: "round";
1508
+ readonly strokeLinejoin: "round";
1509
+ };
1510
+ /**
1511
+ * Path data by tool id, plus a few keys a host toolbar needs that are not
1512
+ * themselves tools (`cursor`, the group headers).
1513
+ *
1514
+ * Values are the `d` attribute of one `<path>`. Multiple subpaths are joined
1515
+ * into the same string rather than split across elements, so a host renders one
1516
+ * node per glyph.
1517
+ */
1518
+ declare const DRAWING_TOOL_ICONS: Readonly<Record<string, string>>;
1519
+ /**
1520
+ * The glyph for a tool, or `undefined` when it has none.
1521
+ *
1522
+ * Undefined rather than a placeholder: a host that renders an empty box has a
1523
+ * visible gap to fix, while one handed a question mark ships it.
1524
+ */
1525
+ declare function drawingToolIcon(toolId: string): string | undefined;
1526
+ /** Every id this set covers, for a host building a palette from it. */
1527
+ declare function drawingToolIconIds(): string[];
1528
+ /** The viewBox every chrome glyph is authored in. */
1529
+ declare const CHROME_ICON_VIEWBOX = "0 0 16 16";
1530
+ /**
1531
+ * Chrome stroke width in viewBox units. Not the tool stroke scaled (that would
1532
+ * be 1.33): at 16px a glyph needs a touch more relative weight than at 24px to
1533
+ * read as the same line, and 1.5 is where the two rails match by eye.
1534
+ */
1535
+ declare const CHROME_ICON_STROKE = 1.5;
1536
+ /** Attributes a host should apply to the `<svg>` around a chrome glyph. */
1537
+ declare const CHROME_ICON_ATTRS: {
1538
+ readonly viewBox: "0 0 16 16";
1539
+ readonly fill: "none";
1540
+ readonly stroke: "currentColor";
1541
+ readonly strokeWidth: 1.5;
1542
+ readonly strokeLinecap: "round";
1543
+ readonly strokeLinejoin: "round";
1544
+ };
1545
+ /**
1546
+ * Path data for host chrome: the buttons around the chart rather than the
1547
+ * tools in it. Same rules as the tool tier (one path per glyph, no presentation
1548
+ * attributes, integer coordinates) on the 16 grid with a 1..15 live area.
1549
+ *
1550
+ * The pair `cursor` / `magnet` / `text` also exist in the tool registry, at 24.
1551
+ * They are drawn twice on purpose: a rail button and a toolbar button are
1552
+ * different sizes, and the whole point of a second grid is not scaling one
1553
+ * drawing to both.
1554
+ */
1555
+ declare const CHROME_ICONS: Readonly<Record<string, string>>;
1556
+ /**
1557
+ * Chrome glyphs meant to be painted solid. Paths carry no presentation
1558
+ * attributes, so the fill is applied by the wrapper (`chromeIconSvg` does it,
1559
+ * a host with its own wrapper reads this set) and the registry stays pure.
1560
+ */
1561
+ declare const CHROME_ICON_FILLED: ReadonlySet<string>;
1562
+ /** The chrome glyph for an id, or `undefined` when there is none. */
1563
+ declare function chromeIcon(id: string): string | undefined;
1564
+ /** Every id the chrome tier covers. */
1565
+ declare function chromeIconIds(): string[];
1566
+
1567
+ /** Prefix of every `<symbol id>` in the sprite, and of every `<use href>`. */
1568
+ declare const ICON_SYMBOL_PREFIX = "oac-icon-";
1569
+ /** Options shared by the inline builders. */
1570
+ interface IconSvgOptions {
1571
+ /**
1572
+ * Width and height. A number is CSS pixels; a string is written verbatim, so
1573
+ * `'1em'` sizes the glyph with the surrounding text. Default: the grid's
1574
+ * native size (24 for tools, 16 for chrome), where the stroke is crispest.
1553
1575
  */
1554
- private _aimPoint;
1576
+ size?: number | string;
1577
+ /** Stroke width in viewBox units. Default: the tier's `*_STROKE`. */
1578
+ stroke?: number;
1579
+ /** A class for the host's own styling. */
1580
+ className?: string;
1581
+ }
1582
+ /** Options for `toolCursor`. */
1583
+ interface ToolCursorOptions {
1584
+ /** Cursor image size in CSS pixels. Default 20. Browsers reject images over 128. */
1585
+ size?: number;
1586
+ /** The pointer's active pixel, from the image's top-left. Default: the centre. */
1587
+ hotspot?: readonly [number, number];
1588
+ /** Glyph colour. Default white. */
1589
+ color?: string;
1555
1590
  /**
1556
- * The free end of a two-anchor line under angle lock, or null when the lock
1557
- * does not apply: no Shift, a tool without the flag, no anchor yet to
1558
- * measure from, or a host that cannot map pixels (the lock is a screen
1559
- * angle, so there is nothing to lock to in data space).
1591
+ * Halo colour. Default: black under a light `color`, white under a dark one,
1592
+ * judged from a hex colour. A non-hex `color` gets a black halo unless this
1593
+ * is set.
1560
1594
  */
1561
- private _lockedPoint;
1595
+ halo?: string;
1596
+ /** The keyword after the image, for a browser that will not take it. Default `crosshair`. */
1597
+ fallback?: string;
1598
+ }
1599
+ /**
1600
+ * A complete inline `<svg>` for one tool glyph, stroked in `currentColor`.
1601
+ *
1602
+ * ```ts
1603
+ * button.innerHTML = iconSvg('trend-line');
1604
+ * button.innerHTML = iconSvg('trend-line', { size: '1em' });
1605
+ * ```
1606
+ */
1607
+ declare function iconSvg(id: string, opts?: IconSvgOptions): string;
1608
+ /**
1609
+ * A complete inline `<svg>` for one chrome glyph, on the 16 grid. Glyphs in
1610
+ * `CHROME_ICON_FILLED` are painted solid as well as stroked.
1611
+ */
1612
+ declare function chromeIconSvg(id: string, opts?: IconSvgOptions): string;
1613
+ /**
1614
+ * One hidden `<svg>` of `<symbol>`s, for a host that shows many glyphs and
1615
+ * wants each path in the document once. Inject it once, then place glyphs with
1616
+ * `iconUse`. Symbols carry the path and viewBox only; stroke and fill inherit
1617
+ * from the `<svg>` around each `<use>`, so one sprite serves every weight.
1618
+ *
1619
+ * Default: every tool glyph. Repeated ids collapse to one symbol, since a
1620
+ * duplicate element id is an invalid document.
1621
+ */
1622
+ declare function iconSprite(ids?: readonly string[]): string;
1623
+ /** An `<svg>` that references a symbol from `iconSprite`. Same frame as `iconSvg`. */
1624
+ declare function iconUse(id: string, opts?: IconSvgOptions): string;
1625
+ /**
1626
+ * A CSS `cursor` value carrying the tool's glyph, for the canvas while that
1627
+ * tool is armed.
1628
+ *
1629
+ * The glyph is drawn twice: once in `halo`, one pixel wider on each side, and
1630
+ * once in `color` on top, so it reads on a light chart and a dark one without
1631
+ * the host choosing per theme. The value is `url("data:image/svg+xml,...") x y,
1632
+ * fallback`, ready for `canvas.style.cursor`.
1633
+ */
1634
+ declare function toolCursor(id: string, opts?: ToolCursorOptions): string;
1635
+
1636
+ /**
1637
+ * A `DrawingLayer` renders the drawings of one pane and answers the chart's
1638
+ * hit-test. Anchors live in `{ time, price }`, so the layer maps them through
1639
+ * the *fractional* index helpers: the gapless axis means an anchor can sit
1640
+ * between bars (inside a collapsed weekend) or past the last one (a forward
1641
+ * projection), and whole-index lookups have nothing to return there.
1642
+ *
1643
+ * Each pane carries **two** layers, one at z-order `bottom` for drawings with a
1644
+ * negative `zIndex` (under the series) and one at `top` for the rest. The top
1645
+ * one takes over handles and hit-testing for the pair through `setBelow`, so a
1646
+ * shape parked under the candles still shows its grab handles above them and
1647
+ * a click lands on whatever the eye sees on top.
1648
+ *
1649
+ * Hit ids are `draw:<id>` for the body and `draw:<id>#<n>` for anchor `n`, so
1650
+ * the controller can tell "move the whole shape" from "move this handle".
1651
+ *
1652
+ * The hover ring, the magnet ring and the hover handles are all overlay
1653
+ * state: they change on every pointer move, so they must only ever cost the
1654
+ * top canvas. The layer that paints them is the one whose `requestUpdate`
1655
+ * the chart maps to the cursor tier, which is why the bottom layer of a pair
1656
+ * stores that state and asks for nothing.
1657
+ */
1658
+
1659
+ /** Which side of the series a layer paints on. */
1660
+ type DrawingLayerOrder = 'bottom' | 'top';
1661
+ /** The pointer kinds the layer sizes its targets for. */
1662
+ type DrawingPointerKind = 'mouse' | 'touch' | 'pen';
1663
+ /**
1664
+ * Paint order: by `zIndex`, ties by array position. `Array.prototype.sort` is
1665
+ * stable, which is what makes the tie rule hold without a second key.
1666
+ */
1667
+ declare function sortByZIndex(drawings: readonly Drawing[]): Drawing[];
1668
+ declare class DrawingLayer implements IPrimitive {
1669
+ private readonly _order;
1670
+ /** In paint order. */
1671
+ private _drawings;
1672
+ private _host;
1673
+ private _selected;
1674
+ /** The drawing under the pointer, whether or not it is selected. */
1675
+ private _hovered;
1676
+ /** Where the next click will land while the magnet is pulling it. */
1677
+ private _snap;
1678
+ /** Anchors of the in-progress drawing, plus the live cursor point. */
1679
+ private _preview;
1680
+ /** The layer under this one, whose handles and hits this layer answers for. */
1681
+ private _below;
1682
+ /** The layer that has taken over this one's handles and hit-testing. */
1683
+ private _above;
1684
+ /** Sizes grab targets for the device last seen. */
1685
+ private _touch;
1686
+ constructor(order?: DrawingLayerOrder);
1687
+ attached(host: PrimitiveHost): void;
1688
+ detached(): void;
1689
+ zOrder(): ZOrder;
1690
+ /** Drawings overlay the price range; they never drive it. */
1691
+ autoscaleInfo(): null;
1692
+ setDrawings(drawings: readonly Drawing[]): void;
1693
+ setSelected(ids: readonly string[]): void;
1562
1694
  /**
1563
- * The nearest O/H/L/C of the hovered bar, at that bar's time, when the
1564
- * magnet pulls; null when it does not. `strong` always pulls; `weak` only
1565
- * within a few pixels, measured on screen so the pull is the same reach at
1566
- * every zoom. Price panes only: an indicator pane's values are not prices.
1695
+ * The drawing under the pointer. Its handles paint at a lighter weight than
1696
+ * a selection's, as the hint that it can be grabbed. Repaints only from the
1697
+ * layer that paints handles: the adopted bottom layer keeps the id for its
1698
+ * own bookkeeping and asks for nothing, since its repaint costs the series.
1567
1699
  */
1568
- private _snapPoint;
1569
- private _onDrag;
1570
- /** Apply one drag frame to the model, from the gesture's snapshot. */
1571
- private _moveDrag;
1572
- /** How far down the screen `to` is from `from` on one pane, in media px. */
1573
- private _pixelDelta;
1574
- /** An anchor in container media px, or null on a host without the mapping. */
1575
- private _toPixel;
1576
- /** The inverse of `_toPixel`. */
1577
- private _fromPixel;
1700
+ setHovered(id: string | null): void;
1701
+ hovered(): string | null;
1578
1702
  /**
1579
- * `free` projected onto the nearest 45 degree ray from `anchor`, all in
1580
- * screen space: the angle the eye reads is the one on the canvas, and a log
1581
- * scale or a tall pane would make a data-space angle anything but. The
1582
- * projection rather than a rotation, so a level line still ends under the
1583
- * pointer's x and a vertical one under its y; only the stray axis is
1584
- * dropped. Null when the host cannot map pixels, or the two coincide.
1703
+ * The point the magnet will snap the next click to, or null when it is not
1704
+ * pulling. Painted as a hollow ring so the user sees the anchor land before
1705
+ * committing to it.
1585
1706
  */
1586
- private _lockAngle;
1587
- private _onDragEnd;
1707
+ setSnapPoint(point: DrawingPoint | null): void;
1708
+ snapPoint(): DrawingPoint | null;
1588
1709
  /**
1589
- * The pair of layers for a pane, made on first use. The bottom one is added
1590
- * first so a host that lists primitives sees them in paint order; the top one
1591
- * adopts it so handles and hit-tests come from one place.
1710
+ * Size the grab targets for the device in use. Touch doubles the radii; a
1711
+ * mouse or a pen keeps the desktop sizes. The render context may carry the
1712
+ * same fact (`pointerType`), and when it does that wins per call, so a
1713
+ * first touch on a fresh chart is already sized right.
1592
1714
  */
1593
- private _layerFor;
1594
- /** Whether a drawing paints on the top layer: over the series, or lifted for a drag. */
1595
- private _onTop;
1596
- /** Push the current list into each pane's layers and into the chart state. */
1597
- private _sync;
1715
+ setPointerType(kind: DrawingPointerKind | null | undefined): void;
1716
+ setPreview(drawing: Drawing | null): void;
1598
1717
  /**
1599
- * The per-frame half of a drag: only the top layers of the panes the
1600
- * gesture touches are re-listed, so the repaint stays on the cursor tier.
1601
- * Everything moving is on a top layer by then (anything under the series
1602
- * was lifted when the gesture began), and the bottom layers have not
1603
- * changed since, so re-listing them would cost a series repaint for
1604
- * nothing.
1718
+ * Adopt the layer under this one. From then on this layer paints the handles
1719
+ * of both and answers `hitTest` for both, and the adopted layer paints bodies
1720
+ * only. Handles have to live up here: a selected drawing under the series
1721
+ * would otherwise have its handles buried under the candles, and a handle
1722
+ * you cannot see is a handle you cannot grab. Pass null to release.
1605
1723
  */
1606
- private _syncDrag;
1724
+ setBelow(layer: DrawingLayer | null): void;
1725
+ /** Repaint for overlay-only state, from the layer that paints it. */
1726
+ private _requestOverlay;
1727
+ /** Whether targets are sized for a fingertip on this call. */
1728
+ private _isTouch;
1729
+ private _grabRadius;
1730
+ private _handleRadius;
1731
+ /** Map an anchor to media px on this pane. */
1732
+ private _project;
1733
+ private _points;
1734
+ /** Selected, unlocked drawings of this layer, in paint order. */
1735
+ private _handled;
1607
1736
  /**
1608
- * Mirror the in-progress anchors (plus the cursor) into the preview slot.
1609
- * The cursor point goes through the same aim as a click would, so the
1610
- * preview shows the locked angle or the snapped anchor before it lands.
1737
+ * The hovered drawing of this layer, when it is one that could be grabbed
1738
+ * and is not already showing selection handles.
1611
1739
  */
1612
- private _syncPreview;
1740
+ private _hoverHandled;
1741
+ draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
1742
+ private _drawingContext;
1743
+ private _drawContent;
1744
+ private _drawPlacementGuide;
1613
1745
  /**
1614
- * Show where the magnet will land the next click, or nothing. A ring only
1615
- * while a click would place an anchor: a tool armed, not a brush (which
1616
- * inks where the pointer is), and the pull actually applying at the cursor.
1617
- * Angle lock bypasses the magnet, so it hides the ring too.
1746
+ * Anchor handles. A hover shows them light (thin, translucent) as a hint
1747
+ * that the shape can be grabbed; a selection shows them at full weight.
1618
1748
  */
1619
- private _syncSnapRing;
1620
- private _pushUndo;
1749
+ private _drawHandles;
1750
+ /** The magnet ring: hollow, in the axis text colour, at the snap point. */
1751
+ private _drawSnapRing;
1752
+ hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
1753
+ private _hitHandle;
1754
+ private _hitBody;
1621
1755
  }
1622
1756
 
1623
1757
  /**
@@ -1825,4 +1959,4 @@ declare const PATTERN_DRAWING_TOOLS: readonly DrawingTool[];
1825
1959
 
1826
1960
  declare const DRAW_TIER: "draw";
1827
1961
 
1828
- export { ADVANCED_GEOMETRY_TOOLS, ADVANCED_LINE_TOOLS, ALIGN_OPTIONS, ARC, ARROW, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, BALLOON, BRUSH, BUILTIN_DRAWING_TOOLS, CALLOUT, CHROME_ICONS, CHROME_ICON_ATTRS, CHROME_ICON_FILLED, CHROME_ICON_STROKE, CHROME_ICON_VIEWBOX, CIRCLE, COLOR_FIELD, COMMENT, CROSS_LINE, CURVE, CYCLE_PALETTE, CYCLIC_LINES, type ClipboardPort, DATE_RANGE, DEFAULT_FIB, DEFAULT_FIB_FAN, DEFAULT_FIB_TIME_ZONE, DEFAULT_GANN_BOX, DEFAULT_GANN_FAN, DOUBLE_CURVE, DRAWING_CLIPBOARD_KEY, DRAWING_CLIPBOARD_VERSION, DRAWING_STATE_VERSION, DRAWING_TOOL_ICONS, DRAW_TIER, type DrawContext, type Drawing, type DrawingChangeKind, type DrawingChartHost, DrawingClipboard, type DrawingClipboardOptions, DrawingController, type DrawingControllerOptions, type DrawingInput, type DrawingKeyAction, type DrawingKeyContext, type DrawingKeyEvent, DrawingLayer, type DrawingLayerOrder, type DrawingPatch, type DrawingPoint, type DrawingPointerKind, type DrawingStyle, type DrawingText, type DrawingTool, type DrawingValueContext, type DrawingsDocument, ELLIPSE, EXTENDED_LINE, EXTEND_FIELDS, type ExpandContext, FIB_CHANNEL, FIB_EXTENSION, FIB_FAN, FIB_RETRACEMENT, FIB_TIME_ZONE, FILL_FIELDS, FLAG_MARK, FONT_FIELDS, FONT_OPTIONS, FORECAST, type FibLevel, type FieldGroup, type FieldKind, GANN_BOX, GANN_FAN, HIGHLIGHTER, HORIZONTAL_LINE, HORIZONTAL_RAY, type HitContext, ICON_ATTRS, ICON_STROKE, ICON_SYMBOL_PREFIX, ICON_VIEWBOX, type IconAttrs, type IconSvgOptions, LEVEL_FIELDS, LEVEL_NEUTRAL, LINE_FIELDS, LINE_STYLE_FIELD, LINE_STYLE_OPTIONS, LINE_WIDTH_FIELD, LONG_POSITION, MEASURE, type MagnetMode, NOTE, NUDGE_STEP_PX, NUDGE_STEP_SHIFT_PX, PARALLEL_CHANNEL, PATH, PATTERN_DRAWING_TOOLS, PLATE_TEXT_FIELDS, POLYLINE, PRICE_LABEL, PRICE_NOTE, PRICE_RANGE, RAY, RECTANGLE, ROTATED_RECTANGLE, SHAPE_TEXT_FIELDS, SHORT_POSITION, SHOW_LABELS_FIELD, SIGNPOST, SINE_LINE, type ScreenPoint, type SettingsField, type SettingsSchema, type ShortcutEvent, TABLE, TEXT, TEXT_FIELDS, TEXT_POSITION_OPTIONS, TEXT_VALUE_FIELD, TIME_CYCLES, TREND_LINE, TRIANGLE, type ToolCursorOptions, VALIGN_OPTIONS, VERTICAL_LINE, applyDrawingSettings, boundsOf, catmullRom, chromeIcon, chromeIconIds, chromeIconSvg, clearMemoryClipboard, cloneDrawing, cloneLevels, coerceSettingValue, composeSettings, cycleColor, decodeClipboardPayload, distToEllipse, distToLine, distToPolyline, distToRect, distToSegment, drawingSettingsSchema, drawingShortcuts, drawingToolIcon, drawingToolIconIds, encodeClipboardPayload, extendSegment, formatRatio, gannLabel, getDrawingTool, hasDrawingTool, iconSprite, iconSvg, iconUse, keyToDrawingAction, levelColor, matchDrawingShortcut, migrateDrawings, pressureWidth, rdpSimplify, readDrawingSetting, readDrawingSettings, rectOf, registerBuiltinDrawingTools, registerDrawingTool, registeredDrawingTools, sanitizeDrawing, sortByZIndex, systemClipboard, toolCursor };
1962
+ export { ADVANCED_GEOMETRY_TOOLS, ADVANCED_LINE_TOOLS, ALIGN_OPTIONS, ANCHORED_VWAP, ARC, ARROW, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, type AnalysisProfileRow, type AnalysisStatus, type AnchoredVwapOptions, type AnchoredVwapPoint, type AnchoredVwapResult, type AnchoredVwapSource, BALLOON, BRUSH, BUILTIN_DRAWING_TOOLS, CALLOUT, CHROME_ICONS, CHROME_ICON_ATTRS, CHROME_ICON_FILLED, CHROME_ICON_STROKE, CHROME_ICON_VIEWBOX, CIRCLE, COLOR_FIELD, COMMENT, CROSS_LINE, CURVE, CYCLE_PALETTE, CYCLIC_LINES, type ClipboardPort, DATE_RANGE, DEFAULT_FIB, DEFAULT_FIB_FAN, DEFAULT_FIB_TIME_ZONE, DEFAULT_GANN_BOX, DEFAULT_GANN_FAN, DOUBLE_CURVE, DRAWING_CLIPBOARD_KEY, DRAWING_CLIPBOARD_VERSION, DRAWING_STATE_VERSION, DRAWING_TOOL_ICONS, DRAW_TIER, type DrawContext, type Drawing, type DrawingChangeKind, type DrawingChartHost, DrawingClipboard, type DrawingClipboardOptions, DrawingController, type DrawingControllerOptions, type DrawingInput, type DrawingKeyAction, type DrawingKeyContext, type DrawingKeyEvent, DrawingLayer, type DrawingLayerOrder, type DrawingLinkChart, type DrawingLinkContext, type DrawingLinkContextSource, DrawingLinkGroup, type DrawingLinkOptions, type DrawingPatch, type DrawingPoint, type DrawingPointerKind, type DrawingStyle, type DrawingText, type DrawingTool, type DrawingValueContext, type DrawingsDocument, ELLIPSE, EXTENDED_LINE, EXTEND_FIELDS, type ExpandContext, FIB_CHANNEL, FIB_EXTENSION, FIB_FAN, FIB_RETRACEMENT, FIB_TIME_ZONE, FILL_FIELDS, FIXED_RANGE_VOLUME_PROFILE, FLAG_MARK, FONT_FIELDS, FONT_OPTIONS, FORECAST, type FibLevel, type FieldGroup, type FieldKind, type FixedRangeVolumeProfileOptions, type FixedRangeVolumeProfileResult, GANN_BOX, GANN_FAN, HIGHLIGHTER, HORIZONTAL_LINE, HORIZONTAL_RAY, type HitContext, ICON_ATTRS, ICON_STROKE, ICON_SYMBOL_PREFIX, ICON_VIEWBOX, type IconAttrs, type IconSvgOptions, LEVEL_FIELDS, LEVEL_NEUTRAL, LINE_FIELDS, LINE_STYLE_FIELD, LINE_STYLE_OPTIONS, LINE_WIDTH_FIELD, LONG_POSITION, MEASURE, type MagnetMode, NOTE, NUDGE_STEP_PX, NUDGE_STEP_SHIFT_PX, PARALLEL_CHANNEL, PATH, PATTERN_DRAWING_TOOLS, PLATE_TEXT_FIELDS, POLYLINE, PRICE_LABEL, PRICE_NOTE, PRICE_RANGE, RAY, RECTANGLE, ROTATED_RECTANGLE, SHAPE_TEXT_FIELDS, SHORT_POSITION, SHOW_LABELS_FIELD, SIGNPOST, SINE_LINE, type ScreenPoint, type SettingsField, type SettingsSchema, type ShortcutEvent, TABLE, TEXT, TEXT_FIELDS, TEXT_POSITION_OPTIONS, TEXT_VALUE_FIELD, TIME_CYCLES, TREND_LINE, TRIANGLE, type ToolCursorOptions, VALIGN_OPTIONS, VERTICAL_LINE, anchoredVwapAnalysis, applyDrawingSettings, boundsOf, catmullRom, chromeIcon, chromeIconIds, chromeIconSvg, clearMemoryClipboard, cloneDrawing, cloneLevels, coerceSettingValue, composeSettings, createDrawingLinkGroup, cycleColor, decodeClipboardPayload, distToEllipse, distToLine, distToPolyline, distToRect, distToSegment, drawingSettingsSchema, drawingShortcuts, drawingToolIcon, drawingToolIconIds, encodeClipboardPayload, extendSegment, fixedRangeVolumeProfileAnalysis, formatRatio, gannLabel, getDrawingTool, hasDrawingTool, iconSprite, iconSvg, iconUse, keyToDrawingAction, levelColor, matchDrawingShortcut, migrateDrawings, pressureWidth, rdpSimplify, readDrawingSetting, readDrawingSettings, rectOf, registerBuiltinDrawingTools, registerDrawingTool, registeredDrawingTools, sanitizeDrawing, sortByZIndex, systemClipboard, toolCursor };