openalgo-charts 2.5.7 → 2.5.9

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,9 +1,10 @@
1
- import { AlertDrawingValue, AlertDrawingLevel, PrimitiveRenderContext, Bar, PriceScaleId, IndicatorApi, IPrimitive, DataLayer, PlotRect, AlertDrawingInfo, PrimitiveHost, ZOrder, PrimitiveHit } from 'openalgo-charts';
1
+ import { AlertDrawingValue, AlertDrawingLevel, PrimitiveRenderContext, Bar, IPrimitive, DataLayer, PlotRect, IndicatorApi, SeriesApi, PriceScaleId, 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
5
5
  * dialog, expressed as dot paths into the drawing (`style.color`,
6
- * `text.fontSize`, `props.foo`, `zIndex`, `space`) with a control kind and a label.
6
+ * `text.fontSize`, `props.foo`, `intervals.from`, `zIndex`, `space`) with a
7
+ * control kind and a label.
7
8
  *
8
9
  * The rule the whole module exists for: a tool declares only fields its `draw`
9
10
  * actually reads. A schema is not a wish list. A host renders exactly what is
@@ -14,14 +15,19 @@ import { AlertDrawingValue, AlertDrawingLevel, PrimitiveRenderContext, Bar, Pric
14
15
  * lives in tools.ts so this file has no import that could loop back here.
15
16
  */
16
17
 
17
- type FieldKind = 'color' | 'number' | 'select' | 'lineStyle' | 'boolean' | 'text' | 'opacity' | 'levels';
18
+ /**
19
+ * The control a field wants. `interval` is a chart interval code, which the
20
+ * host offers from its own interval list (the engine has none), with an
21
+ * empty choice for no limit.
22
+ */
23
+ type FieldKind = 'color' | 'number' | 'select' | 'lineStyle' | 'boolean' | 'text' | 'opacity' | 'levels' | 'interval';
18
24
  /** The section a host groups a field under. */
19
- type FieldGroup = 'line' | 'fill' | 'text' | 'levels' | 'behavior';
25
+ type FieldGroup = 'line' | 'fill' | 'text' | 'levels' | 'behavior' | 'visibility';
20
26
  interface SettingsField {
21
27
  /**
22
- * Dot path into the drawing. Two segments under `style`, `text` or `props`
23
- * (`style.lineWidth`), or one of the top-level fields `locked`, `visible`,
24
- * `zIndex`, `space`.
28
+ * Dot path into the drawing. Two segments under `style`, `text`, `props`
29
+ * or `intervals` (`style.lineWidth`, `intervals.to`), or one of the
30
+ * top-level fields `locked`, `visible`, `zIndex`, `space`.
25
31
  */
26
32
  path: string;
27
33
  label: string;
@@ -91,6 +97,15 @@ declare const EXTEND_FIELDS: readonly SettingsField[];
91
97
  * keeps its place and only stops (or starts) following the bars.
92
98
  */
93
99
  declare const SPACE_FIELD: SettingsField;
100
+ /**
101
+ * The intervals a drawing is shown on (`Drawing.intervals`), as two interval
102
+ * codes, each end included and either one left empty for no limit. No tool
103
+ * declares them, since the engine cannot list a host's intervals: a host that
104
+ * offers visibility per interval adds them to a tool's schema with
105
+ * `composeSettings`, and `applyDrawingSettings` writes the pair as the patch's
106
+ * `intervals`, with both ends cleared meaning every interval.
107
+ */
108
+ declare const INTERVAL_FIELDS: readonly SettingsField[];
94
109
  declare const SHOW_LABELS_FIELD: SettingsField;
95
110
  declare const LEVEL_FIELDS: readonly SettingsField[];
96
111
  /**
@@ -140,7 +155,9 @@ declare function coerceSettingValue(field: SettingsField, raw: unknown): unknown
140
155
  * partial a controller's `update` accepts. Bags come back whole
141
156
  * (`style: { ...d.style, color }`), so it does not matter whether the
142
157
  * controller merges or replaces them. A value of `undefined` removes the key,
143
- * which is how a host offers "reset to default".
158
+ * which is how a host offers "reset to default". The `intervals` pair comes
159
+ * back whole as well, as the range to replace the drawing's; with neither end
160
+ * left it is `{}`, which a controller takes as no range, every interval.
144
161
  *
145
162
  * With a `schema`, each value is coerced to its field's kind and any path the
146
163
  * schema does not declare is dropped: a host can hand over its form state as
@@ -172,6 +189,14 @@ declare function applyDrawingSettings(d: Drawing, patch: Record<string, unknown>
172
189
  * their own so a time or a price never has to mean a pixel. The field is
173
190
  * optional and additive, which is why the document stays version 2: a save
174
191
  * with no viewport drawing is byte for byte what it was.
192
+ *
193
+ * Version 3 added one field, {@link Drawing.intervals}: the range of chart
194
+ * intervals a drawing is shown on. A version 2 document is a valid version 3
195
+ * one and loads unchanged, and a document is written as version 3 only when a
196
+ * drawing in it carries a range, so a save without one is still version 2.
197
+ * The version is raised for a range because an earlier build would not keep
198
+ * it: its migration drops the field, and the drawing would show on every
199
+ * interval there and lose its range on the next save.
175
200
  */
176
201
 
177
202
  /** One anchor, in data space. */
@@ -328,6 +353,19 @@ interface DrawingPolicy {
328
353
  /** `false`: left out of the object inventory (`ChartObjects`) and every panel built on it. */
329
354
  listed?: boolean;
330
355
  }
356
+ /**
357
+ * The chart intervals a drawing is shown on, both ends included, as interval
358
+ * codes the chart's data context names (`'1m'`, `'1h'`, `'D'`, or a code the
359
+ * host registered). An absent end is no limit on that side, so `{ to: '1h' }`
360
+ * shows the drawing up to hourly bars. Intervals compare by bar length, so the
361
+ * two ends may be written either way round. See `drawingShownOnInterval`.
362
+ */
363
+ interface DrawingIntervalRange {
364
+ /** The shortest interval the drawing is shown on. */
365
+ from?: string;
366
+ /** The longest interval the drawing is shown on. */
367
+ to?: string;
368
+ }
331
369
  interface Drawing {
332
370
  id: string;
333
371
  /** Registered tool id. */
@@ -361,6 +399,13 @@ interface Drawing {
361
399
  policy?: DrawingPolicy;
362
400
  /** Default true. */
363
401
  visible?: boolean;
402
+ /**
403
+ * The chart intervals the drawing is shown on. Absent means every interval.
404
+ * On an interval outside the range the drawing is kept and saved but not
405
+ * on the chart: it is not painted, hit-tested, boxed or erased there, and
406
+ * the object inventory marks it. `visible` stays the user's own switch.
407
+ */
408
+ intervals?: DrawingIntervalRange;
364
409
  /**
365
410
  * Paint order. Below zero paints under the series, at or above zero paints
366
411
  * over it. Ties break by array order, so two drawings at 0 paint in the
@@ -406,6 +451,11 @@ type DrawingInput = Omit<Drawing, 'id' | 'zIndex' | 'createdAt'> & {
406
451
  type DrawingPatch = Partial<Pick<Drawing, 'points' | 'style' | 'text' | 'props' | 'locked' | 'visible' | 'zIndex' | 'policy' | 'space' | 'viewportPoints'>> & {
407
452
  /** A series-band entry to paint directly above, or null to leave the series band. */
408
453
  stackAbove?: string | null;
454
+ /**
455
+ * The intervals to show the drawing on, replacing any range it had, or
456
+ * null (or a range with neither end) to show it on every interval.
457
+ */
458
+ intervals?: DrawingIntervalRange | null;
409
459
  };
410
460
  /**
411
461
  * What `DrawingController.placeInStack` puts a drawing next to: another
@@ -416,20 +466,29 @@ type DrawingStackTarget = {
416
466
  } | {
417
467
  entry: string;
418
468
  };
419
- /** The persisted shape's version; bumped when {@link Drawing} changes. */
420
- declare const DRAWING_STATE_VERSION = 2;
421
469
  /**
422
- * What `toJSON` returns and `ChartState.drawings` carries. Versioned so a 1.9.x
423
- * save (a bare `Drawing[]`) is recognisable and upgraded rather than misread.
470
+ * The newest document version this build reads and writes; bumped when
471
+ * {@link Drawing} changes in a way an earlier build would lose. A document is
472
+ * written as the lowest version that holds it (see {@link DrawingsDocument}).
424
473
  */
474
+ declare const DRAWING_STATE_VERSION = 3;
425
475
  /** A named set of drawing ids. A drawing belongs to at most one group. */
426
476
  interface DrawingGroup {
427
477
  id: string;
428
478
  name: string;
429
479
  members: string[];
430
480
  }
481
+ /**
482
+ * What `toJSON` returns and `ChartState.drawings` carries. Versioned so a 1.9.x
483
+ * save (a bare `Drawing[]`) is recognisable and upgraded rather than misread.
484
+ */
431
485
  interface DrawingsDocument {
432
- version: 2;
486
+ /**
487
+ * 3 when a drawing carries an interval range, else 2: the lowest version
488
+ * that holds the content, so an earlier build reads a document without a
489
+ * range exactly as it wrote one.
490
+ */
491
+ version: 2 | 3;
433
492
  drawings: Drawing[];
434
493
  groups?: DrawingGroup[];
435
494
  }
@@ -692,9 +751,12 @@ declare function fixedRangeVolumeProfileAnalysis(bars: readonly Bar[], fromTime:
692
751
  */
693
752
  declare const DRAWING_CLIPBOARD_KEY = "openalgo-charts/drawings";
694
753
  /**
695
- * Payload format version. Tracks the model version, since the body *is* a
696
- * drawings document: version 1 carried 1.9.x drawings, version 2 carries the
697
- * split text and levelled fibs.
754
+ * The newest payload version this build reads. Tracks the model version, since
755
+ * the body *is* a drawings document: version 1 carried 1.9.x drawings,
756
+ * version 2 carries the split text and levelled fibs, and version 3 adds the
757
+ * interval range a drawing is shown on. A payload is written as the lowest
758
+ * version that holds it, so a copy with no range still pastes into a build
759
+ * that reads only version 2, which refuses anything newer.
698
760
  */
699
761
  declare const DRAWING_CLIPBOARD_VERSION: number;
700
762
  /** The async slice of `navigator.clipboard` this module uses. */
@@ -780,46 +842,12 @@ declare class DrawingClipboard {
780
842
  read(): Promise<Omit<Drawing, 'id'>[] | null>;
781
843
  }
782
844
 
783
- /** Where a study's price input is picked and anchored: a pane, and a scale on it. */
784
- interface StudyInputTarget {
785
- paneIndex: number;
786
- priceScaleId: PriceScaleId;
787
- }
788
- /**
789
- * One anchor move as an undo step, walked by the drawing history or by the
790
- * host's timeline it was handed to (`DrawingController.delegateInputAnchorSteps`).
791
- * Each call writes the other side's point, and is false, writing nothing, once
792
- * the study no longer holds the point it starts from.
793
- */
794
- interface InputAnchorStep {
795
- undo(): boolean;
796
- redo(): boolean;
797
- }
798
- /**
799
- * The pane and scale a study's `price` input is picked on and anchored to,
800
- * or null when that cannot be told. An explicit `pick` target with both
801
- * halves is used as given. Otherwise the study's own plots decide: the price
802
- * belongs where they are drawn, which must be one scale on one pane (and
803
- * inside any half the descriptor did name), since a price read off the wrong
804
- * scale is a different number.
805
- */
806
- declare function studyInputTarget(chart: {
807
- panes?(): readonly unknown[];
808
- }, study: IndicatorApi, key: string): StudyInputTarget | null;
809
-
810
845
  /**
811
- * Drawing controller: the interaction and persistence layer over
812
- * `DrawingLayer`. It is **headless**: no DOM, no toolbar. A host sets the
813
- * active tool (from its own button, a shortcut, a command palette) and the
814
- * controller runs placement, selection, dragging, undo, and serialisation.
815
- *
816
- * It listens on the chart's event bus (`click`, `crosshair:move`, `drag`,
817
- * `drag:end`) rather than the single-slot `subscribeClick`/`subscribeDrag`
818
- * callbacks, so a host keeps using those for its own order lines.
819
- *
820
- * Selection is a list. Every method that edits takes the whole list into one
821
- * undo entry, so a multi-drag, a batch delete or a paste of ten shapes is one
822
- * Ctrl+Z, which is what the hand that did it expects.
846
+ * The public shapes of the drawing controller: the slice of the chart it
847
+ * drives, its options, and the events and edit options its methods take.
848
+ * Kept apart from the controller so the class reads as behaviour, and so a
849
+ * module that needs one of these (the gestures read the gesture switches)
850
+ * names it without importing the controller itself.
823
851
  */
824
852
 
825
853
  /**
@@ -903,6 +931,19 @@ interface DrawingChartHost {
903
931
  * puts the price pane below its studies; without it the price pane is slot 0.
904
932
  */
905
933
  primaryPaneIndex?(): number;
934
+ /**
935
+ * Optional, all three, for the magnet: the price series' bars, the studies
936
+ * and a series' style. The chart reports no bar while a drawing is in hand,
937
+ * so a handle or a shape snaps against `primaryBars`; a study pane snaps
938
+ * to the values of the studies plotted on it, skipping a hidden plot. A
939
+ * host without them snaps placements on the price pane only.
940
+ */
941
+ primaryBars?(): readonly Bar[];
942
+ indicators?(): readonly IndicatorApi[];
943
+ seriesStyle?(series: SeriesApi): {
944
+ readonly visible?: boolean;
945
+ readonly color?: string;
946
+ } | null;
906
947
  /**
907
948
  * Optional, both: a pane's series band, back to front, and the call that
908
949
  * paints a layer directly above one of its entries. Without them no drawing
@@ -911,6 +952,20 @@ interface DrawingChartHost {
911
952
  */
912
953
  seriesStack?(paneIndex: number): readonly string[];
913
954
  setPrimitiveStackAbove?(primitive: IPrimitive, above: string | null): boolean;
955
+ /**
956
+ * Optional: the host's data context, whose `interval` decides which
957
+ * drawings with an interval range are shown (`Drawing.intervals`). Read
958
+ * when the controller is built and on every `data:context`, whose payload
959
+ * is the context itself; a host without it that emits `data:context` is
960
+ * followed through the payload alone. With no interval every drawing shows.
961
+ * The instrument is declared too, as the chart's context carries it, so one
962
+ * host object also satisfies `DrawingLinkChart`.
963
+ */
964
+ getDataContext?(): {
965
+ readonly symbol?: string;
966
+ readonly exchange?: string;
967
+ readonly interval?: string;
968
+ } | undefined;
914
969
  }
915
970
  interface DrawingControllerOptions {
916
971
  /**
@@ -960,6 +1015,46 @@ interface DrawingControllerOptions {
960
1015
  * in settings and picked with `Chart.beginPick('point')`.
961
1016
  */
962
1017
  inputAnchors?: boolean;
1018
+ /**
1019
+ * The pointer gestures a held modifier key starts, each on unless set to
1020
+ * false here, for a host whose own chart gestures already use that key.
1021
+ * `setOptions` merges it flag by flag.
1022
+ */
1023
+ gestures?: DrawingGestureOptions;
1024
+ }
1025
+ /**
1026
+ * The modifier gestures `DrawingControllerOptions.gestures` turns off. Ctrl
1027
+ * means Cmd as well, for macOS. None of them is a key chord, so none can
1028
+ * shadow one of `matchDrawingShortcut` or `keyToDrawingAction`.
1029
+ */
1030
+ interface DrawingGestureOptions {
1031
+ /**
1032
+ * Ctrl held while placing an anchor or dragging a handle or a shape: the
1033
+ * strong magnet for as long as it is held, whatever `magnet` is set to.
1034
+ */
1035
+ snapModifier?: boolean;
1036
+ /**
1037
+ * Shift+click on empty chart space, with no tool armed: a ruler from the
1038
+ * click to the pointer, gone on the next click or `cancel()`. A preview,
1039
+ * never a drawing: not saved, not an undo step, never linked.
1040
+ */
1041
+ measure?: boolean;
1042
+ /**
1043
+ * Ctrl plus a drag on empty chart space, with no tool armed: a box that
1044
+ * selects every drawing whose geometry it touches, as a click there would
1045
+ * find it, leaving out drawings that are hidden, locked or unselectable.
1046
+ * Shift held as well adds them to the selection. While Ctrl is held over
1047
+ * empty space the chart is in placement mode, so the press is not a pan.
1048
+ */
1049
+ boxSelect?: boolean;
1050
+ /**
1051
+ * Alt (Option) plus a drag on a drawing's body: the drawing stays where it
1052
+ * is and a copy of it moves instead, as one undo step. The whole movable
1053
+ * selection is copied, as a plain drag would move it, and each copy is the
1054
+ * user's own drawing, with no policy and no link lineage. A copy waits for
1055
+ * the pointer to travel three pixels, so a jitter leaves none behind.
1056
+ */
1057
+ dragCopy?: boolean;
963
1058
  }
964
1059
  /** How `DrawingController.setTool` arms a tool. */
965
1060
  interface DrawingPlacementOptions {
@@ -1018,10 +1113,57 @@ interface DrawingEditOptions {
1018
1113
  */
1019
1114
  force?: boolean;
1020
1115
  }
1116
+
1117
+ /** Where a study's price input is picked and anchored: a pane, and a scale on it. */
1118
+ interface StudyInputTarget {
1119
+ paneIndex: number;
1120
+ priceScaleId: PriceScaleId;
1121
+ }
1122
+ /**
1123
+ * One anchor move as an undo step, walked by the drawing history or by the
1124
+ * host's timeline it was handed to (`DrawingController.delegateInputAnchorSteps`).
1125
+ * Each call writes the other side's point, and is false, writing nothing, once
1126
+ * the study no longer holds the point it starts from.
1127
+ */
1128
+ interface InputAnchorStep {
1129
+ undo(): boolean;
1130
+ redo(): boolean;
1131
+ }
1132
+ /**
1133
+ * The pane and scale a study's `price` input is picked on and anchored to,
1134
+ * or null when that cannot be told. An explicit `pick` target with both
1135
+ * halves is used as given. Otherwise the study's own plots decide: the price
1136
+ * belongs where they are drawn, which must be one scale on one pane (and
1137
+ * inside any half the descriptor did name), since a price read off the wrong
1138
+ * scale is a different number.
1139
+ */
1140
+ declare function studyInputTarget(chart: {
1141
+ panes?(): readonly unknown[];
1142
+ }, study: IndicatorApi, key: string): StudyInputTarget | null;
1143
+
1144
+ /**
1145
+ * Drawing controller: the interaction and persistence layer over
1146
+ * `DrawingLayer`. It is **headless**: no DOM, no toolbar. A host sets the
1147
+ * active tool (from its own button, a shortcut, a command palette) and the
1148
+ * controller runs placement, selection, dragging, undo, and serialisation.
1149
+ *
1150
+ * It listens on the chart's event bus (`click`, `crosshair:move`, `drag`,
1151
+ * `drag:end`) rather than the single-slot `subscribeClick`/`subscribeDrag`
1152
+ * callbacks, so a host keeps using those for its own order lines.
1153
+ *
1154
+ * Selection is a list. Every method that edits takes the whole list into one
1155
+ * undo entry, so a multi-drag, a batch delete or a paste of ten shapes is one
1156
+ * Ctrl+Z, which is what the hand that did it expects.
1157
+ */
1158
+
1021
1159
  declare class DrawingController {
1022
1160
  private readonly _chart;
1023
1161
  private _opts;
1024
1162
  private readonly _clipboard;
1163
+ /** Every conversion between data space and the screen. */
1164
+ private readonly _screen;
1165
+ /** The gestures that make no drawing: the temporary measure, box select and the eraser. */
1166
+ private readonly _gestures;
1025
1167
  private readonly _layers;
1026
1168
  private _drawings;
1027
1169
  private _groups;
@@ -1048,6 +1190,16 @@ declare class DrawingController {
1048
1190
  private _slotKey;
1049
1191
  /** Shift as of the last pointer report: what angle lock reads mid-preview. */
1050
1192
  private _shift;
1193
+ /** Ctrl or Cmd as of the last pointer report: the strong magnet while held. */
1194
+ private _strong;
1195
+ /** Placement mode as this controller last set it. */
1196
+ private _placing;
1197
+ /** Drawings an eraser drag has touched: still in the model, left unpainted until it lets go. */
1198
+ private _hidden;
1199
+ /** The chart interval drawings are shown for; see `interval()`. */
1200
+ private _interval;
1201
+ /** The drawings the chart's interval hid when the layers were last listed; see `_followInterval`. */
1202
+ private _offInterval;
1051
1203
  /** The device behind the last pointer report, for target sizing. */
1052
1204
  private _pointerKind;
1053
1205
  /** Snapshots for undo/redo; each is a full drawing list (they are small). */
@@ -1092,10 +1244,33 @@ declare class DrawingController {
1092
1244
  * Guarded so a base bundle predating `setPlacementMode` still loads the tier.
1093
1245
  */
1094
1246
  private _setPlacementMode;
1247
+ /**
1248
+ * The armed tool's placement mode, or a gesture's. The gestures are asked even with a tool
1249
+ * armed: their answer is also how they read the next press, and a stale one would take it.
1250
+ */
1251
+ private _placementWanted;
1095
1252
  activeTool(): string | null;
1096
1253
  setOptions(patch: DrawingControllerOptions): void;
1097
1254
  /** The snap mode in force, after the boolean form has been folded. */
1098
1255
  magnetMode(): MagnetMode;
1256
+ /**
1257
+ * Whether a temporary measure (Shift+click on empty space) is on the chart.
1258
+ * `draw:measure` (`{ active }`) fires when one starts and when it goes. A
1259
+ * host routing Escape to `cancel()` only while placing passes this too.
1260
+ */
1261
+ measuring(): boolean;
1262
+ /**
1263
+ * Eraser mode: a click on a drawing deletes it, and a drag deletes every
1264
+ * drawing it crosses, as one undo step on release. What the user could not
1265
+ * delete by selecting it (read-only, locked, unselectable or hidden) stays.
1266
+ * While it is on the chart is in placement mode, so a drag erases rather
1267
+ * than pans. Turning it on disarms any tool; arming a tool, `cancel()` and
1268
+ * `setEraser(false)` turn it off. `draw:eraser` (`{ active }`) fires on
1269
+ * each change.
1270
+ */
1271
+ setEraser(active: boolean): void;
1272
+ /** Whether eraser mode is on. */
1273
+ erasing(): boolean;
1099
1274
  /**
1100
1275
  * The drawing under the pointer, selected or not, as the chart's hit-test
1101
1276
  * last reported it. What a host passes as `hasTarget` to the key mapping,
@@ -1104,11 +1279,6 @@ declare class DrawingController {
1104
1279
  hovered(): string | null;
1105
1280
  /** The clipboard behind copy / cut / paste, for a host reporting failures. */
1106
1281
  clipboard(): DrawingClipboard;
1107
- /**
1108
- * Every drawing, in list order. That is creation order until a z-order call
1109
- * moves one; the list is the tie-break for equal `zIndex`, so it is also the
1110
- * paint order within a band.
1111
- */
1112
1282
  /** Named drawing sets, returned as detached records. */
1113
1283
  groups(): readonly DrawingGroup[];
1114
1284
  /**
@@ -1159,8 +1329,42 @@ declare class DrawingController {
1159
1329
  /** The drawings of one slot of a pane, in paint order. */
1160
1330
  private _slotMembers;
1161
1331
  private _remapPanes;
1332
+ /**
1333
+ * Every drawing, in list order, those the interval hides included. That is
1334
+ * creation order until a z-order call moves one; the list is the tie-break
1335
+ * for equal `zIndex`, so it is also the paint order within a band.
1336
+ */
1162
1337
  drawings(): readonly Drawing[];
1163
1338
  get(id: string): Drawing | undefined;
1339
+ /**
1340
+ * The chart interval drawings are shown for: the data context's `interval`
1341
+ * when the controller was built, then as each `data:context` announces it,
1342
+ * or null when the host names none (or a blank one), and then every drawing
1343
+ * shows. Each drawing's `intervals` range is read against it.
1344
+ */
1345
+ interval(): string | null;
1346
+ /**
1347
+ * Whether a drawing is on the chart at the chart's interval: false for an
1348
+ * unknown id and for one whose `intervals` range leaves that interval out.
1349
+ * `visible` is not read; it is the user's own switch.
1350
+ */
1351
+ shownOnInterval(id: string): boolean;
1352
+ /**
1353
+ * The ids of the drawings the chart's interval leaves off the chart, in
1354
+ * model order. One pass for a caller asking about every drawing, as the
1355
+ * object inventory does on each refresh: `shownOnInterval` per id would
1356
+ * look each one up.
1357
+ */
1358
+ hiddenOnInterval(): string[];
1359
+ /** The test of whether a drawing is shown at the chart's interval, resolved once for a pass over many. */
1360
+ private _shownFilter;
1361
+ /**
1362
+ * Follow a change of the chart's interval: what it hides leaves the layers
1363
+ * and the selection, what it shows comes back. The layers are listed again
1364
+ * only when that set changed, since a list under the series costs the
1365
+ * series a repaint and a new symbol on the same interval changes nothing.
1366
+ */
1367
+ private _followInterval;
1164
1368
  get isDestroyed(): boolean;
1165
1369
  /** Apply a linked commit without adding to this chart's local undo history. */
1166
1370
  applyLinkedDrawing(id: string, drawing: Drawing | null): void;
@@ -1330,14 +1534,6 @@ declare class DrawingController {
1330
1534
  private _offsetAnchors;
1331
1535
  /** Nudge every anchor so a pasted copy is not hidden under its original. */
1332
1536
  private _offsetPoints;
1333
- /**
1334
- * Move a price down the screen by `px`. Done per anchor rather than as one
1335
- * price delta so the move is a rigid *screen* translation, which is what the
1336
- * eye expects and what keeps a shape's proportions on a log scale.
1337
- */
1338
- private _offsetPrice;
1339
- /** Move a time right along the screen by `px`. */
1340
- private _offsetTime;
1341
1537
  /**
1342
1538
  * Move a study's input anchor (a price input declared with `timeKey` and
1343
1539
  * `anchor: true`) to `point` as the user, the way dragging its handle does:
@@ -1431,28 +1627,11 @@ declare class DrawingController {
1431
1627
  private _setHovered;
1432
1628
  /** Remember the device behind a report and size the layers' targets for it. */
1433
1629
  private _notePointer;
1434
- /**
1435
- * The positions a pressed move passed through, as anchors, ending on the
1436
- * move's own point. The samples carry pixels (container x, pane-local y);
1437
- * the payload's point is the same position in its own space, so the gap
1438
- * between the two is the pane's offset, and each sample maps back through
1439
- * the host's converters. A host without them, or a payload without
1440
- * samples, inks the one point the move reports.
1441
- */
1442
- private _coalesced;
1443
- /** A pressure worth storing: finite, and not the mouse's stand-in. */
1444
- private _pressureOf;
1445
1630
  /**
1446
1631
  * Let a tool turn the clicked anchors into its full set (the position tools
1447
1632
  * build a 1:1 box off one click). Identity for tools without the hook.
1448
1633
  */
1449
1634
  private _expand;
1450
- /**
1451
- * Bar spacing in seconds, read from the last gap in the data. A one-bar chart
1452
- * has no gap to read, so fall back to a minute rather than answering zero and
1453
- * producing zero-width defaults and invisible paste offsets.
1454
- */
1455
- private _barSeconds;
1456
1635
  private _isFreehand;
1457
1636
  /**
1458
1637
  * Append one sample to the stroke in progress. Points arriving closer than a
@@ -1472,7 +1651,6 @@ declare class DrawingController {
1472
1651
  * a pixel one; a host that cannot map to pixels keeps every sample.
1473
1652
  */
1474
1653
  private _finishFreehand;
1475
- private _thinStroke;
1476
1654
  /**
1477
1655
  * End a variable-anchor shape (polyline, path) at the anchors placed so far.
1478
1656
  * Those tools declare `points: 0`, so nothing else can ever complete them;
@@ -1515,24 +1693,42 @@ declare class DrawingController {
1515
1693
  */
1516
1694
  private _lockedPoint;
1517
1695
  /**
1518
- * The nearest O/H/L/C of the hovered bar, at that bar's time, when the
1519
- * magnet pulls; null when it does not. `strong` always pulls; `weak` only
1520
- * within a few pixels, measured on screen so the pull is the same reach at
1521
- * every zoom. Price panes only: an indicator pane's values are not prices.
1696
+ * Where the magnet lands `point`, or null when it does not pull: the
1697
+ * nearest O/H/L/C of `bar` on the price pane, the nearest plotted value on
1698
+ * a study pane (`snap.ts`). Ctrl held pulls as the strong magnet whatever
1699
+ * the mode. A placement reads the bar the chart reported under the
1700
+ * pointer; a drag, which reports none, passes the bar under its time.
1522
1701
  */
1523
1702
  private _snapPoint;
1703
+ /** Shift and Ctrl (Cmd) as the last pointer report carried them: the angle lock and the strong magnet. */
1704
+ private _noteKeys;
1705
+ /**
1706
+ * The anchor of a grabbed shape the magnet lands: the one nearest the
1707
+ * press, since what the hand is closest to is what it means to put down.
1708
+ */
1709
+ private _grabbedAnchor;
1710
+ /**
1711
+ * A shape's move with the magnet's pull on its grabbed anchor applied, or
1712
+ * null when nothing pulls: the whole shape shifts by what lands that one
1713
+ * anchor on the value, so it keeps its form.
1714
+ */
1715
+ private _pullShape;
1524
1716
  private _onDrag;
1717
+ /** Whether a drag has left its press by more than the chart's click slop, on screen. */
1718
+ private _travelled;
1719
+ /**
1720
+ * Copies of `sources` for a drag to move, in the model and selected. A
1721
+ * copy is the user's own drawing, as a duplicate is: no policy, a fresh
1722
+ * id, and `_insert` drops the link lineage.
1723
+ */
1724
+ private _copies;
1725
+ /** A cancelled copy leaves nothing: its copies go, and the selection is what they were copied from. */
1726
+ private _dropCopies;
1525
1727
  private _emitDragPreview;
1526
1728
  /** Roll back an interrupted drag and leave the pre-gesture undo/redo stacks intact. */
1527
1729
  cancelDrag(): boolean;
1528
1730
  /** Apply one drag frame to the model, from the gesture's snapshot. */
1529
1731
  private _moveDrag;
1530
- /** How far down the screen `to` is from `from` on one pane, in media px. */
1531
- private _pixelDelta;
1532
- /** An anchor in container media px, or null on a host without the mapping. */
1533
- private _toPixel;
1534
- /** The inverse of `_toPixel`. */
1535
- private _fromPixel;
1536
1732
  /**
1537
1733
  * The drawing's anchors in container media px, the space `timeToCoordinate`
1538
1734
  * and `priceToCoordinate` answer in, whichever space it is anchored in. What
@@ -1541,68 +1737,8 @@ declare class DrawingController {
1541
1737
  * a strip, or hidden behind a maximized pane).
1542
1738
  */
1543
1739
  screenPoints(id: string): ScreenPoint[] | null;
1544
- /** A pane's price projection, when the host exposes one. */
1545
- private _pane;
1546
- /**
1547
- * Where a pane's plot is and how big, or null when it has none on screen
1548
- * (folded to a strip, or hidden behind a maximized pane): a fraction of
1549
- * either would be a fraction of nothing. It needs a pane projection too,
1550
- * since every gesture reads its y back through one.
1551
- */
1552
- private _plotFrame;
1553
- /**
1554
- * A gesture's position on its pane's plot, in media px. y reads the price
1555
- * back through the pane's readout scale, the exact inverse of how the chart
1556
- * read it; x is the pointer's container x less the plot's left edge, or,
1557
- * for a payload without one, the time through the time axis.
1558
- */
1559
- private _gesturePlot;
1560
- /**
1561
- * Where a drag was pressed, on its pane's plot. Read from the press's time
1562
- * and price when the chart reports them, so the first move is measured from
1563
- * the press and not from itself; a chart with fewer than two bars has no
1564
- * time axis to read a position back from, so it measures from the first move.
1565
- */
1566
- private _dragOrigin;
1567
- /**
1568
- * Data anchors as fractions of their pane's plot at the view on screen, or
1569
- * null when it has none. What is on screen stays where it is; a drawing part
1570
- * way or wholly off the plot comes onto it, since once pinned no pan could
1571
- * bring it back. One that fits moves in whole. One wider or taller than the
1572
- * plot is cut to it on that axis instead, so every handle of a pinned box
1573
- * is on screen to be grabbed.
1574
- */
1575
- private _toViewport;
1576
- /**
1577
- * The inverse of `_toViewport`: fractions back to time and price at the view
1578
- * on screen, from where the drawing is painted, so it does not move.
1579
- */
1580
- private _fromViewport;
1581
- /**
1582
- * Anchors in plot px as the fractions a pinned drawing stores, moved first
1583
- * so its box lies inside the plot. Every gesture ends here, so what is
1584
- * stored is what is painted, and no drag can leave the box where the
1585
- * pointer cannot reach it.
1586
- */
1587
- private _pinPlot;
1588
- /**
1589
- * Pinned anchors moved by a screen distance in media px, from where the
1590
- * drawing is painted rather than from what it stores: a note the layer
1591
- * holds in from a stored place off the plot (a host's value, a larger
1592
- * chart) moves at once, with no dead travel before it starts.
1593
- */
1594
- private _shiftPinned;
1595
1740
  /** Put a drawing's anchors back as a gesture found them. */
1596
1741
  private _restoreAnchors;
1597
- /**
1598
- * `free` projected onto the nearest 45 degree ray from `anchor`, all in
1599
- * screen space: the angle the eye reads is the one on the canvas, and a log
1600
- * scale or a tall pane would make a data-space angle anything but. The
1601
- * projection rather than a rotation, so a level line still ends under the
1602
- * pointer's x and a vertical one under its y; only the stray axis is
1603
- * dropped. Null when the host cannot map pixels, or the two coincide.
1604
- */
1605
- private _lockAngle;
1606
1742
  private _onDragEnd;
1607
1743
  /**
1608
1744
  * The pair of layers for a pane, made on first use. The bottom one is added
@@ -1766,6 +1902,215 @@ declare class DrawingLinkGroup {
1766
1902
  }
1767
1903
  declare function createDrawingLinkGroup(options?: DrawingLinkOptions): DrawingLinkGroup;
1768
1904
 
1905
+ /**
1906
+ * Drawings per instrument: one drawing document for each instrument a chart
1907
+ * shows, kept in a store the host chooses, and swapped as the chart moves
1908
+ * from one instrument to another.
1909
+ *
1910
+ * A trader's levels belong to the symbol they were drawn on. The controller
1911
+ * holds one document and knows nothing of instruments (the engine has no
1912
+ * instrument concept), so without this a trend line drawn on one symbol stays
1913
+ * on screen for every symbol loaded after it, and deleting it anywhere
1914
+ * deletes it everywhere.
1915
+ *
1916
+ * The rules this keeps, each of which a host would otherwise have to get right
1917
+ * on its own:
1918
+ *
1919
+ * - **The instrument comes from the chart's data context.** A `data:context`
1920
+ * naming another symbol or exchange saves the outgoing document and loads
1921
+ * the incoming one, in the same turn, so nothing that listens after it (an
1922
+ * alert, a link group) ever sees one instrument's drawings under another's
1923
+ * name. An interval or a data variant is the same instrument, and a context
1924
+ * that names no instrument changes nothing.
1925
+ * - **A swap is not an edit.** It records no undo step, and it clears the
1926
+ * drawing undo history the way any `fromJSON` does: a step taken on one
1927
+ * instrument describes that instrument's drawings, and taking it back on
1928
+ * another would put one of them there. A drag in progress is put back first
1929
+ * and a shape half placed is dropped, with the tool left armed.
1930
+ * - **The whole document swaps**, drawings pinned to the viewport included: a
1931
+ * group or a stacking order can span both spaces, and a note pinned to the
1932
+ * screen is nearly always about the instrument on it. Transient drawings
1933
+ * (`policy.persistent` false) are the host's and are not saved; a host
1934
+ * keeping one per instrument places it again after the swap.
1935
+ * - **Every committed change is written at once**, only when the saved
1936
+ * document actually changed, so a reload loses nothing and a stream of
1937
+ * updates to transient drawings writes nothing. An instrument left with no
1938
+ * drawings has its entry removed rather than an empty one kept.
1939
+ * - **A store that fails loses nothing for the session.** A refused write is
1940
+ * reported through `onError` and the document is held in memory, read back
1941
+ * from there, and written again with the next change.
1942
+ * - **Anything else that replaces the whole document** (a host's `fromJSON`,
1943
+ * a chart layout restored) is the current instrument's new document, and is
1944
+ * written as such.
1945
+ * - **A stored document of an earlier version is read through the migration**
1946
+ * and written back only when something in it changes, in the version that
1947
+ * holds it then: a version 2 document stays version 2 until a drawing in it
1948
+ * is given an interval range, and a version 3 one keeps its ranges.
1949
+ *
1950
+ * The store is synchronous on purpose: a swap happens inside the context
1951
+ * change, and an answer arriving later would land one instrument's drawings
1952
+ * on whatever the chart shows by then. A host whose drawings live on a
1953
+ * server keeps a synchronous copy here and syncs it in the background.
1954
+ */
1955
+
1956
+ /** An instrument as a chart's data context names it. */
1957
+ interface DrawingInstrument {
1958
+ symbol?: string;
1959
+ exchange?: string;
1960
+ }
1961
+ /**
1962
+ * Where the documents live, one per instrument key. The host's choice:
1963
+ * `memoryDrawingStore` (the default), `webStorageDrawingStore` over a web
1964
+ * storage the host hands it, or its own. Synchronous; a throw from any
1965
+ * method, or `set` returning false, is a failure the helper reports.
1966
+ */
1967
+ interface DrawingDocumentStore {
1968
+ /** The document stored under `key`, or null (or undefined) when there is none. */
1969
+ get(key: string): unknown;
1970
+ /** Store `document` under `key`. False, or a throw, when the write did not land. */
1971
+ set(key: string, document: DrawingsDocument): boolean | void;
1972
+ /** Forget whatever is stored under `key`. */
1973
+ remove(key: string): void;
1974
+ }
1975
+ /** The three members of a web storage `webStorageDrawingStore` uses. */
1976
+ interface DrawingTextStorage {
1977
+ getItem(key: string): string | null;
1978
+ setItem(key: string, value: string): void;
1979
+ removeItem(key: string): void;
1980
+ }
1981
+ /** The slice of the chart `InstrumentDrawings` needs. */
1982
+ interface InstrumentDrawingsChart {
1983
+ readonly isDestroyed?: boolean;
1984
+ on(event: string, handler: (payload: unknown) => void): () => void;
1985
+ getDataContext?(): Readonly<DrawingInstrument> | undefined;
1986
+ }
1987
+ /** A store operation that failed, as `InstrumentDrawingsOptions.onError` receives it. */
1988
+ interface InstrumentDrawingsError {
1989
+ operation: 'read' | 'write' | 'remove';
1990
+ key: string;
1991
+ error: unknown;
1992
+ }
1993
+ interface InstrumentDrawingsOptions {
1994
+ /** Where the documents live. Default: `memoryDrawingStore()`, for the life of the page. */
1995
+ store?: DrawingDocumentStore;
1996
+ /**
1997
+ * The key an instrument's document is stored under, or null for a context
1998
+ * that names no instrument. Default `instrumentDrawingsKey`. A host that
1999
+ * wants drawings per data variant too, or one namespace per chart, says so here.
2000
+ */
2001
+ key?: (instrument: DrawingInstrument) => string | null;
2002
+ /**
2003
+ * Which document wins when the helper starts on an instrument the store
2004
+ * already holds one for while the controller holds another. `'stored'`
2005
+ * (default) loads the stored one, which is right for a chart built fresh.
2006
+ * `'live'` keeps the controller's, even an empty one, and writes it to the
2007
+ * store, for a host that has just loaded that instrument's drawings itself
2008
+ * (a layout, a chart rebuilt from the one it replaces). Either way, drawings the
2009
+ * controller holds for an instrument the store has nothing for are kept as
2010
+ * that instrument's: that is how a document saved before drawings were per
2011
+ * instrument is attached to the instrument it was drawn on.
2012
+ */
2013
+ prefer?: 'stored' | 'live';
2014
+ /** Called for every store operation that failed. The document stays in memory for the session. */
2015
+ onError?: (error: InstrumentDrawingsError) => void;
2016
+ }
2017
+ /**
2018
+ * The default key: the exchange and the symbol, `NSE:INFY`, or the symbol
2019
+ * alone when there is no exchange. Each part is URI-encoded, so a colon
2020
+ * inside a symbol cannot make two instruments one key. Null when the symbol
2021
+ * is missing or blank. Case is kept: the host decides whether `infy` and
2022
+ * `INFY` are one instrument, and the widget uppercases symbols itself.
2023
+ */
2024
+ declare function instrumentDrawingsKey(instrument: DrawingInstrument | null | undefined): string | null;
2025
+ /** A store in memory, for the life of the page. Each document is kept as text, so no caller shares an object with it. */
2026
+ declare function memoryDrawingStore(): DrawingDocumentStore;
2027
+ /**
2028
+ * A store over a web storage the host hands it (the page's `localStorage`,
2029
+ * or anything with the same three members), one JSON entry per instrument
2030
+ * under `prefix`. A text that does not parse throws from `get`, which the
2031
+ * helper reports and treats as no drawings.
2032
+ */
2033
+ declare function webStorageDrawingStore(storage: DrawingTextStorage, prefix: string): DrawingDocumentStore;
2034
+ /**
2035
+ * Attach a document saved before drawings were kept per instrument (one set
2036
+ * for the whole chart) to the instrument it was saved with, so no one loses
2037
+ * the drawings they already have. It is written only when the store holds
2038
+ * nothing for that instrument yet and the document has something in it; an
2039
+ * instrument that already has its own keeps it. True when it was written.
2040
+ */
2041
+ declare function migrateUnscopedDrawings(store: DrawingDocumentStore, key: string | null, document: unknown): boolean;
2042
+ /**
2043
+ * Keeps a drawing controller's document per instrument. Build it once the
2044
+ * controller exists; it follows the chart's data context from then on.
2045
+ *
2046
+ * ```ts
2047
+ * const scoped = new InstrumentDrawings(chart, draw, {
2048
+ * store: webStorageDrawingStore(localStorage, 'my-app:drawings:'),
2049
+ * });
2050
+ * chart.setDataContext({ symbol: 'INFY', exchange: 'NSE', interval: '5m' });
2051
+ * ```
2052
+ */
2053
+ declare class InstrumentDrawings {
2054
+ private readonly _draw;
2055
+ private readonly _store;
2056
+ private readonly _keyOf;
2057
+ private readonly _onError;
2058
+ private _key;
2059
+ /** The current instrument's document as last written or loaded, to skip a write that changes nothing. */
2060
+ private _text;
2061
+ /** Documents whose write failed, by key: what the store should hold, kept for the session. */
2062
+ private readonly _held;
2063
+ private _swapping;
2064
+ private _destroyed;
2065
+ private readonly _off;
2066
+ constructor(chart: InstrumentDrawingsChart, controller: DrawingController, options?: InstrumentDrawingsOptions);
2067
+ get isDestroyed(): boolean;
2068
+ /** The key of the instrument whose drawings are on the chart, or null before the chart has named one. */
2069
+ key(): string | null;
2070
+ /**
2071
+ * Move to another instrument now, without waiting for the chart's data
2072
+ * context: for a host that does not publish one, or that switches its
2073
+ * drawings ahead of its data. A later context naming the same instrument
2074
+ * changes nothing. Null, or an instrument with no key, changes nothing.
2075
+ */
2076
+ setInstrument(instrument: DrawingInstrument | null): void;
2077
+ /**
2078
+ * The saved document of an instrument: the drawings on the chart for the
2079
+ * current one, the stored document for any other, or null when it has
2080
+ * none (or no key). A copy either way.
2081
+ */
2082
+ document(instrument: DrawingInstrument): DrawingsDocument | null;
2083
+ /**
2084
+ * Replace one instrument's drawings. On the current instrument that is the
2085
+ * controller's `fromJSON`, which clears its undo history; on any other, the
2086
+ * stored document, shown when the chart next moves there. For a layout
2087
+ * that brings the drawings of an instrument the chart is about to show.
2088
+ */
2089
+ setDocument(instrument: DrawingInstrument, document: unknown): void;
2090
+ /** Write the current instrument's document now, and any the store refused before. False while one is still refused. */
2091
+ save(): boolean;
2092
+ /** Stop following the chart. The documents stay where they are. */
2093
+ destroy(): void;
2094
+ private _keyFor;
2095
+ /** The drawings the controller would save, as text. */
2096
+ private _live;
2097
+ /** Take `key` as the current instrument, with the drawings `prefer` picks. */
2098
+ private _start;
2099
+ private _follow;
2100
+ private _swap;
2101
+ /** Put `document` on the controller without the change it announces being written back. */
2102
+ private _load;
2103
+ private _changed;
2104
+ /** Write the current document when it changed, or always when `force`. */
2105
+ private _saveCurrent;
2106
+ private _write;
2107
+ /** The stored document for `key`, migrated to the current shape, or null. A held one comes first. */
2108
+ private _read;
2109
+ private _report;
2110
+ }
2111
+ /** `new InstrumentDrawings(chart, controller, options)`, as a function. */
2112
+ declare function createInstrumentDrawings(chart: InstrumentDrawingsChart, controller: DrawingController, options?: InstrumentDrawingsOptions): InstrumentDrawings;
2113
+
1769
2114
  /**
1770
2115
  * Built-in drawing tools + the tool registry. Same philosophy as the chart-type
1771
2116
  * and indicator registries: a tool is a descriptor, the layer just runs it, and
@@ -2346,6 +2691,11 @@ declare function toolCursor(id: string, opts?: ToolCursorOptions): string;
2346
2691
  * top canvas. The layer that paints them is the one whose `requestUpdate`
2347
2692
  * the chart maps to the cursor tier, which is why the bottom layer of a pair
2348
2693
  * stores that state and asks for nothing.
2694
+ *
2695
+ * A hit test asks a tool for its distance only where the drawing can be: each
2696
+ * layer keeps a box per drawing (src/draw/hit-index.ts) and a pointer outside
2697
+ * it costs four comparisons. The answer is the one a test of every drawing
2698
+ * gives, because a box covers every point its tool would report as a hit.
2349
2699
  */
2350
2700
 
2351
2701
  /**
@@ -2378,12 +2728,22 @@ declare class DrawingLayer implements IPrimitive {
2378
2728
  private _above;
2379
2729
  /** Sizes grab targets for the device last seen. */
2380
2730
  private _touch;
2731
+ /** Hit boxes per drawing, kept while nothing that places them changes. */
2732
+ private readonly _index;
2733
+ /** Paint positions of the selected, unlocked, shown drawings, or null until asked again. */
2734
+ private _selectedAt;
2381
2735
  constructor(order?: DrawingLayerOrder);
2382
2736
  attached(host: PrimitiveHost): void;
2383
2737
  detached(): void;
2384
2738
  zOrder(): ZOrder;
2385
2739
  /** Drawings overlay the price range; they never drive it. */
2386
2740
  autoscaleInfo(): null;
2741
+ /**
2742
+ * The drawings this layer paints and answers for. The hit boxes kept for
2743
+ * the previous list all go, so a drawing edited in place must be handed
2744
+ * over again, as the controller does after every edit, for a hover to see
2745
+ * where it now is.
2746
+ */
2387
2747
  setDrawings(drawings: readonly Drawing[]): void;
2388
2748
  setSelected(ids: readonly string[]): void;
2389
2749
  /**
@@ -2446,6 +2806,17 @@ declare class DrawingLayer implements IPrimitive {
2446
2806
  /** The magnet ring: hollow, in the axis text colour, at the snap point. */
2447
2807
  private _drawSnapRing;
2448
2808
  hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
2809
+ /**
2810
+ * Paint positions of the drawings `_handled` lists, less the registry check,
2811
+ * which is read live: a tool registered after the list was made makes its
2812
+ * drawings handled from then on, with no new list to say so.
2813
+ */
2814
+ private _selectedPositions;
2815
+ /**
2816
+ * A drawing's body box: none for one that cannot be hit, everywhere for a
2817
+ * tool the box table does not know, else its tool's box at this radius.
2818
+ */
2819
+ private _measure;
2449
2820
  private _hitHandle;
2450
2821
  private _hitBody;
2451
2822
  }
@@ -2521,7 +2892,7 @@ declare const NUDGE_STEP_SHIFT_PX = 10;
2521
2892
  declare function keyToDrawingAction(e: DrawingKeyEvent, ctx: DrawingKeyContext): DrawingKeyAction | null;
2522
2893
 
2523
2894
  /**
2524
- * The 1.9.x to 2.0 drawing migration.
2895
+ * The drawing migration: 1.9.x to 2.0, and document version 2 to 3.
2525
2896
  *
2526
2897
  * Hosts persist `toJSON()` verbatim, and a 1.9.x host has done so for a long
2527
2898
  * time: a bare `Drawing[]` per pane in local storage, for a great many users.
@@ -2554,19 +2925,36 @@ declare function keyToDrawingAction(e: DrawingKeyEvent, ctx: DrawingKeyContext):
2554
2925
  * - Garbage yields an empty document. This runs on the load path, where an
2555
2926
  * exception would take the whole chart down with it.
2556
2927
  *
2557
- * Idempotent on a version 2 document, so a host can call it on every load.
2928
+ * Version 3 added one optional field, the interval range a drawing is shown
2929
+ * on, so a version 2 document needs no upgrade and comes back unchanged,
2930
+ * version and all. A range is kept when it names at least one bound, and the
2931
+ * document out is version 3 only when a drawing kept one. A document from a
2932
+ * later version is read the same lenient way: what this build knows is kept
2933
+ * and the rest dropped, since refusing it would empty the chart on load.
2934
+ *
2935
+ * Idempotent on a version 2 or 3 document, so a host can call it on every load.
2558
2936
  */
2559
2937
 
2560
2938
  /**
2561
2939
  * Upgrade saved drawings to the current document shape. Accepts a 1.9.x
2562
- * `Drawing[]` or a {@link DrawingsDocument}. Every field is validated, the
2563
- * 1.9.x text keys are lifted out of the style bag into `text`, bare level
2564
- * ratios become coloured levels, and array order is kept. An entry that could
2565
- * never be rendered is dropped; anything unparseable yields an empty document
2566
- * rather than an error.
2940
+ * `Drawing[]` or a {@link DrawingsDocument} of any version. Every field is
2941
+ * validated, the 1.9.x text keys are lifted out of the style bag into `text`,
2942
+ * bare level ratios become coloured levels, and array order is kept. An entry
2943
+ * that could never be rendered is dropped; anything unparseable yields an
2944
+ * empty document rather than an error. The result is version 3 when a drawing
2945
+ * carries an interval range and version 2 otherwise.
2567
2946
  */
2568
2947
  declare function migrateDrawings(input: unknown): DrawingsDocument;
2569
2948
 
2949
+ /**
2950
+ * Whether a drawing is shown on a chart whose interval is `interval`. A
2951
+ * drawing with no range is shown on every interval. For a host marking the
2952
+ * drawings a range hides (an objects panel, a settings preview) without a
2953
+ * controller at hand; `DrawingController.shownOnInterval` answers for the
2954
+ * chart the controller is on.
2955
+ */
2956
+ declare function drawingShownOnInterval(drawing: Pick<Drawing, 'intervals'>, interval: string | null | undefined): boolean;
2957
+
2570
2958
  /**
2571
2959
  * Hit-test geometry for the drawing tier. Everything works in media px and
2572
2960
  * returns a distance, so `DrawingLayer` can pick the nearest shape under the
@@ -2660,4 +3048,4 @@ declare const PATTERN_DRAWING_TOOLS: readonly DrawingTool[];
2660
3048
 
2661
3049
  declare const DRAW_TIER: "draw";
2662
3050
 
2663
- 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_ACCENTS, 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_ACCENTS, DRAWING_TOOL_ICONS, DRAW_TIER, type DrawContext, type Drawing, type DrawingChangeEvent, type DrawingChangeKind, type DrawingChartHost, DrawingClipboard, type DrawingClipboardOptions, DrawingController, type DrawingControllerOptions, type DrawingEditOptions, type DrawingGroup, type DrawingInput, type DrawingKeyAction, type DrawingKeyContext, type DrawingKeyEvent, DrawingLayer, type DrawingLayerOrder, type DrawingLinkChart, type DrawingLinkContext, type DrawingLinkContextSource, DrawingLinkGroup, type DrawingLinkOptions, type DrawingPatch, type DrawingPlacementOptions, type DrawingPoint, type DrawingPointerKind, type DrawingPolicy, type DrawingSpace, type DrawingStackTarget, 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, type InputAnchorStep, 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, SPACE_FIELD, SPACE_OPTIONS, type ScreenPoint, type SettingsField, type SettingsSchema, type ShortcutEvent, type StudyInputTarget, TABLE, TEXT, TEXT_FIELDS, TEXT_POSITION_OPTIONS, TEXT_VALUE_FIELD, TIME_CYCLES, TREND_LINE, TRIANGLE, type ToolCursorOptions, VALIGN_OPTIONS, VERTICAL_LINE, type ViewportPoint, anchoredVwapAnalysis, applyDrawingSettings, boundsOf, catmullRom, chromeIcon, chromeIconAccent, chromeIconIds, chromeIconSvg, clearMemoryClipboard, cloneDrawing, cloneLevels, coerceSettingValue, composeSettings, createDrawingLinkGroup, cycleColor, decodeClipboardPayload, distToEllipse, distToLine, distToPolyline, distToRect, distToSegment, drawingSettingsSchema, drawingShortcuts, drawingToolAccent, 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, studyInputTarget, systemClipboard, toolCursor };
3051
+ 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_ACCENTS, 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_ACCENTS, DRAWING_TOOL_ICONS, DRAW_TIER, type DrawContext, type Drawing, type DrawingChangeEvent, type DrawingChangeKind, type DrawingChartHost, DrawingClipboard, type DrawingClipboardOptions, DrawingController, type DrawingControllerOptions, type DrawingDocumentStore, type DrawingEditOptions, type DrawingGestureOptions, type DrawingGroup, type DrawingInput, type DrawingInstrument, type DrawingIntervalRange, type DrawingKeyAction, type DrawingKeyContext, type DrawingKeyEvent, DrawingLayer, type DrawingLayerOrder, type DrawingLinkChart, type DrawingLinkContext, type DrawingLinkContextSource, DrawingLinkGroup, type DrawingLinkOptions, type DrawingPatch, type DrawingPlacementOptions, type DrawingPoint, type DrawingPointerKind, type DrawingPolicy, type DrawingSpace, type DrawingStackTarget, type DrawingStyle, type DrawingText, type DrawingTextStorage, 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, INTERVAL_FIELDS, type IconAttrs, type IconSvgOptions, type InputAnchorStep, InstrumentDrawings, type InstrumentDrawingsChart, type InstrumentDrawingsError, type InstrumentDrawingsOptions, 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, SPACE_FIELD, SPACE_OPTIONS, type ScreenPoint, type SettingsField, type SettingsSchema, type ShortcutEvent, type StudyInputTarget, TABLE, TEXT, TEXT_FIELDS, TEXT_POSITION_OPTIONS, TEXT_VALUE_FIELD, TIME_CYCLES, TREND_LINE, TRIANGLE, type ToolCursorOptions, VALIGN_OPTIONS, VERTICAL_LINE, type ViewportPoint, anchoredVwapAnalysis, applyDrawingSettings, boundsOf, catmullRom, chromeIcon, chromeIconAccent, chromeIconIds, chromeIconSvg, clearMemoryClipboard, cloneDrawing, cloneLevels, coerceSettingValue, composeSettings, createDrawingLinkGroup, createInstrumentDrawings, cycleColor, decodeClipboardPayload, distToEllipse, distToLine, distToPolyline, distToRect, distToSegment, drawingSettingsSchema, drawingShortcuts, drawingShownOnInterval, drawingToolAccent, drawingToolIcon, drawingToolIconIds, encodeClipboardPayload, extendSegment, fixedRangeVolumeProfileAnalysis, formatRatio, gannLabel, getDrawingTool, hasDrawingTool, iconSprite, iconSvg, iconUse, instrumentDrawingsKey, keyToDrawingAction, levelColor, matchDrawingShortcut, memoryDrawingStore, migrateDrawings, migrateUnscopedDrawings, pressureWidth, rdpSimplify, readDrawingSetting, readDrawingSettings, rectOf, registerBuiltinDrawingTools, registerDrawingTool, registeredDrawingTools, sanitizeDrawing, sortByZIndex, studyInputTarget, systemClipboard, toolCursor, webStorageDrawingStore };