openalgo-charts 1.0.8 → 1.0.10

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.
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  **A from-scratch, dependency-free HTML5-canvas charting engine for OpenAlgo.**
6
6
 
7
- Professional interactive financial charts, on-chart trading, and live data - in under 40 KB Brotli, with zero runtime dependencies.
7
+ Professional interactive charts, indicators, drawing tools, order flow, and on-chart trading — six lazy-loaded tiers, zero runtime dependencies, ~33 KB Brotli for the base engine.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/openalgo-charts.svg?color=cb3837&label=npm)](https://www.npmjs.com/package/openalgo-charts)
10
10
  [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE)
11
- [![bundle](https://img.shields.io/badge/brotli-~33%20KB%20base%20%C2%B7%20~58%20KB%20full-brightgreen.svg)](./ARCHITECTURE.md)
11
+ [![bundle](https://img.shields.io/badge/brotli-33%20KB%20base%20%C2%B7%2058%20KB%20all%20tiers-brightgreen.svg)](#size-budget)
12
12
  [![tests](https://img.shields.io/badge/tests-468%20passing-brightgreen.svg)](#develop)
13
13
  [![dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen.svg)](#principles)
14
14
 
@@ -30,7 +30,7 @@ Right-click the chart to place market / limit / stop orders, drag the order and
30
30
 
31
31
  ## Examples gallery
32
32
 
33
- Every chart in the [live gallery](https://marketcalls.github.io/openalgo-charts/examples) is the real library running in your browser - switch tabs, hover the crosshair, drag the order lines. What you see is the code that ran.
33
+ Every chart in the [live gallery](https://marketcalls.github.io/openalgo-charts/examples) is the real library running in your browser - switch tabs, hover the crosshair, drag the order lines, place a drawing. What you see is the code that ran.
34
34
 
35
35
  <p align="center">
36
36
  <img src="docs/demo1.png" alt="Chart-type switcher, custom themes, data tooltips, and event markers" width="49%" />
@@ -54,27 +54,81 @@ const chart = createChart(document.getElementById('chart'));
54
54
  chart.addSeries('candlestick').setData(generateBars(1700000000, 200, 3600));
55
55
  ```
56
56
 
57
- Loadable tiers - lazy-load only what you use:
57
+ ## Tiers
58
58
 
59
- | Import | Contents |
60
- |---|---|
61
- | `openalgo-charts` | Base engine + all standard chart types, indicators, primitives, trading overlay |
62
- | `openalgo-charts/trade` | On-chart order/position/bracket tools + DOM ladder |
63
- | `openalgo-charts/transform` | Renko, Range bars, Point &amp; Figure, Kagi, Line Break, Heikin Ashi |
64
- | `openalgo-charts/profile` | Volume Profile, Market Profile (TPO), Footprint, Order flow |
65
- | `openalgo-charts/indicators` | 18 built-in indicators + the Tier-2 (external-data) contract |
66
- | `openalgo-charts/draw` | 18 drawing tools + a headless drawing controller |
59
+ Import only what you use. Each tier is a separate bundle that registers into the base engine's registries, so the cost of a feature you don't load is zero.
60
+
61
+ | Import | Contents | Brotli |
62
+ |---|---|---|
63
+ | `openalgo-charts` | Engine, 13 chart types, panes &amp; scales, primitives, registries, chart state, trading overlay, OpenAlgo feeds | 32.7 KB |
64
+ | `openalgo-charts/indicators` | 18 built-in indicators + the Tier-2 (external-data) contract | 4.5 KB |
65
+ | `openalgo-charts/draw` | 18 drawing tools + a headless drawing controller | 6.3 KB |
66
+ | `openalgo-charts/transform` | Heikin Ashi, Renko, Range bars, Line Break, Point &amp; Figure, Kagi | 2.7 KB |
67
+ | `openalgo-charts/profile` | Volume Profile, Market Profile (TPO), Footprint, order flow | 5.5 KB |
68
+ | `openalgo-charts/trade` | Order / position / bracket tools + DOM ladder | 6.6 KB |
69
+
70
+ Everything together is **58 KB Brotli**.
67
71
 
68
72
  ## What's built
69
73
 
70
- - **Chart types:** candles, hollow/volume candles, bars, high-low, line, line+markers, step, area, HLC-area, baseline, columns, histogram.
71
- - **Transforms:** Heikin Ashi, Renko, Range bars, Line Break, Point &amp; Figure, Kagi.
72
- - **Profiles &amp; order flow:** Volume Profile, Market Profile (TPO), Footprint, cumulative delta.
73
- - **Indicators:** 18 built-ins via `chart.addIndicator(...)` - SMA, EMA, WMA, VWAP, Bollinger, Supertrend, Parabolic SAR, Ichimoku, RSI, MACD, Stochastic, ADX/DMI, CCI, MFI, ATR, Volume, OBV, A/D - plus a registry for your own, and a Tier-2 contract for indicators with external data (open interest, CVD).
74
- - **Trading:** order/position/bracket lines, live P&amp;L, one-click + drag-to-modify, OCO, validation, analyzer mode, and a depth-of-market ladder (5 to 200 levels).
75
- - **Drawing tools:** 18 tools (trend/ray/fib/channel/position/measure/text/...) with a headless controller - placement, selection, per-anchor drag, magnet snap, undo/redo, and persistence through the chart state.
76
- - **Panes:** draggable dividers, move/maximize/remove, and TradingView-style pane legends with inline show-hide / settings / delete controls.
77
- - **Live + historical** OpenAlgo data (REST history + WebSocket ticks with auto-reconnect), a unified `chart.on(...)` event bus, markers/signals, earnings/dividend/expiry event markers, and custom price/time formatters.
74
+ ### Chart types &amp; transforms
75
+ Candles, hollow and volume candles, OHLC bars, high-low, line, line+markers, step, area, HLC-area, baseline, columns, histogram — plus Heikin Ashi, Renko, Range bars, Line Break, **Point &amp; Figure** (fixed / percent / ATR box sizing, high-low or close construction), and Kagi.
76
+
77
+ ### Indicators
78
+
79
+ ```ts
80
+ import 'openalgo-charts/indicators';
81
+
82
+ chart.addIndicator('bollinger'); // overlays the price pane
83
+ const macd = chart.addIndicator('macd', { fastPeriod: 8 }); // gets its own pane
84
+ macd.setSettings({ 'macd:width': 2, 'macd:lineStyle': 'dashed' });
85
+ ```
86
+
87
+ 18 built-ins: SMA, EMA, WMA, VWAP, Bollinger Bands, Supertrend, Parabolic SAR, Ichimoku Cloud, RSI, MACD, Stochastic, ADX/DMI, CCI, MFI, ATR, Volume, OBV, A/D.
88
+
89
+ The chart owns the whole lifecycle — series, pane placement, reference levels, fixed ranges (RSI 0..100), recompute on data change, teardown. Every plot gets colour, opacity, thickness, and line style for free, generated from the descriptor. Write your own with `registerIndicator`, or use the **Tier-2 contract** for indicators whose data isn't derived from OHLCV (open interest, CVD, any external feed).
90
+
91
+ ### Drawing tools
92
+
93
+ ```ts
94
+ import { DrawingController } from 'openalgo-charts/draw';
95
+
96
+ const draw = new DrawingController(chart, { magnet: true });
97
+ draw.setTool('trend-line'); // the next two clicks place it
98
+ ```
99
+
100
+ 18 tools: trend line, ray, extended line, arrow, horizontal line/ray, vertical line, cross line, rectangle, ellipse, parallel channel, fib retracement/extension, long/short position (with R:R and risk-based sizing), measure, text, path.
101
+
102
+ Headless by design — no toolbar, no dialogs. Placement with live preview, selection, whole-shape and per-anchor dragging, magnet snap to O/H/L/C, undo/redo (a drag is one step), and persistence. Anchors are `{ time, price }`, never pixels, so they survive zoom and resolve inside collapsed session gaps and past the last bar.
103
+
104
+ ### Panes &amp; legends
105
+ Draggable pane dividers, move / maximize / remove, and TradingView-style pane legends showing one reading per plot in that plot's own colour, with inline show-hide / settings / move / delete controls revealed on hover.
106
+
107
+ ### Trading
108
+ Order, position, and bracket lines with live P&amp;L, one-click and drag-to-modify, OCO, validation, an order state machine, analyzer (sandbox) mode, and a depth-of-market ladder (5 to 200 levels).
109
+
110
+ ### Profiles &amp; order flow
111
+ Volume Profile, Market Profile (TPO), Footprint, and cumulative delta.
112
+
113
+ ### State
114
+ `chart.getState()` / `chart.restoreState()` capture the viewport, grid, panes, price scales, indicator instances, and drawings as one JSON payload — saved layouts and templates with no extra storage plumbing.
115
+
116
+ ### Data
117
+ OpenAlgo REST history + WebSocket ticks with auto-reconnect and resubscribe, live candle aggregation, tick/volume bars, a unified `chart.on(...)` event bus, markers and signals, earnings/dividend/expiry event markers, and custom price/time formatters.
118
+
119
+ ## Size budget
120
+
121
+ Enforced in CI by [`size-limit`](./.size-limit.json) — nothing is excluded, because there are no runtime dependencies to exclude.
122
+
123
+ | Bundle | Limit | Actual |
124
+ |---|---|---|
125
+ | Base engine | 34 KB | 32.72 KB |
126
+ | Base + trade | 40.5 KB | 39.31 KB |
127
+ | Indicators tier | 9 KB | 4.47 KB |
128
+ | Draw tier | 14 KB | 6.25 KB |
129
+ | Transform tier | 5 KB | 2.66 KB |
130
+ | Profile tier | 8 KB | 5.53 KB |
131
+ | **Everything** | **72 KB** | **58.22 KB** |
78
132
 
79
133
  ## Documentation
80
134
 
@@ -89,6 +143,16 @@ npm run build # build the library (dist/) the live
89
143
  cd website && npm install && npm run dev # http://localhost:3000/openalgo-charts
90
144
  ```
91
145
 
146
+ ## Examples
147
+
148
+ Runnable demos in [`examples/`](./examples), including a full **yfinance terminal** ([`examples/yfinance`](./examples/yfinance)) with a TradingView-style shell: symbol search, interval pills, chart-type picker, indicator menu, a vertical drawing rail, a floating properties bar, generated indicator settings, and layout persistence.
149
+
150
+ ```bash
151
+ npm run build
152
+ cd examples/yfinance && pip install -r requirements.txt && python server.py
153
+ # → http://127.0.0.1:8000/examples/yfinance/index.html
154
+ ```
155
+
92
156
  ## Develop
93
157
 
94
158
  ```bash
@@ -103,14 +167,25 @@ npm run verify # typecheck + test + build + size
103
167
 
104
168
  ## Principles
105
169
 
106
- - **Single canvas pipeline** (no SVG, no DOM-per-bar) - small and fast.
107
- - **Gapless time axis by default** - weekends, holidays, and session breaks collapse.
108
- - **Zero runtime dependencies** - nothing is excluded from the size budget.
170
+ - **Single canvas pipeline** (no SVG, no DOM-per-bar) — small and fast.
171
+ - **Gapless time axis by default** — weekends, holidays, and session breaks collapse.
172
+ - **Registries, not switches** — chart types, indicators, and drawing tools are all descriptors. Adding one is a registration, never a core change.
173
+ - **Zero runtime dependencies** — nothing is excluded from the size budget.
109
174
  - **Apache-2.0**, original code.
110
175
 
111
176
  ## Status &amp; limitations
112
177
 
113
- Version **1.0.8 (published)** - all engine build phases are implemented with 468 unit tests, base engine ~33 KB Brotli, full package ~58 KB Brotli (all six tiers). The OpenAlgo WS/trade adapters ship and auto-reconnect, but their exact message/endpoint schemas should be verified against your running OpenAlgo build. An optional DOM chrome package (toolbar, dialogs, command palette, objects panel) is the next planned piece; the Footprint/order-flow renderer still needs its visual pass, and overlay and `indexed-to-100` price scales are unimplemented - see [`ARCHITECTURE.md`](./ARCHITECTURE.md) for the honest deferred list.
178
+ Version **1.0.8 (published)**. All engine build phases are implemented with 468 unit tests across 47 files.
179
+
180
+ Known gaps, stated plainly:
181
+
182
+ - The **Footprint / order-flow renderer** works but has not had its visual pass — hardcoded colours (not theme-aware), a single display mode, no `setOptions`, and `stackedImbalances` is computed but not drawn.
183
+ - **Footprint and order flow need trade-by-trade data classified bid/ask.** OpenAlgo does not store this by default, so it is live-session-only unless you add a tick recorder. See [`ARCHITECTURE.md`](./ARCHITECTURE.md) §6A.
184
+ - The OpenAlgo **WS/trade adapter wire schemas** ship with injectable transports and offline tests, but the exact field names should be verified against your running OpenAlgo build.
185
+ - Price-scale **`percentage`** and **`indexed-to-100`** modes, and overlay scales on a shared axis, are not implemented.
186
+ - An optional **DOM chrome package** (toolbar, dialogs, command palette, objects panel) is the next planned piece; today that UI lives in the examples.
187
+
188
+ See [`ARCHITECTURE.md`](./ARCHITECTURE.md) §13a for the full deferred list.
114
189
 
115
190
  ## License
116
191
 
@@ -403,6 +403,19 @@ interface DrawingStyle {
403
403
  wrapWidth?: number;
404
404
  /** Horizontal alignment within the box. Defaults to 'left'. */
405
405
  textAlign?: 'left' | 'center' | 'right';
406
+ /** Vertical placement within the box. Defaults to 'top'. */
407
+ textVAlign?: 'top' | 'middle' | 'bottom';
408
+ /**
409
+ * Where a shape's label sits relative to the shape: `inside` the outline, or
410
+ * `outside` just above it. Shapes only — the text tool *is* its own box.
411
+ */
412
+ textPosition?: 'inside' | 'outside';
413
+ /**
414
+ * Label colour. Shapes need this separate from `color`, which is the outline —
415
+ * a purple rectangle with white text is one shape with two colours.
416
+ * Falls back to `color`.
417
+ */
418
+ fontColor?: string;
406
419
  /** Position tools: capital base and risk per trade, for the size readout. */
407
420
  accountSize?: number;
408
421
  risk?: number;
@@ -815,6 +828,8 @@ declare class Pane {
815
828
  /** Remove a series record if present; returns true if it was found. */
816
829
  removeSeries(record: SeriesRecord): boolean;
817
830
  series(): readonly SeriesRecord[];
831
+ /** Primitives attached to this pane, in draw order. */
832
+ primitives(): readonly IPrimitive[];
818
833
  addPrimitive(primitive: IPrimitive, host: PrimitiveHost): void;
819
834
  /** Remove a primitive if present; returns true if it was found. */
820
835
  removePrimitive(primitive: IPrimitive): boolean;
@@ -1395,6 +1410,53 @@ declare class EventMarkers implements IPrimitive {
1395
1410
  hitTest(x: number, y: number): PrimitiveHit | null;
1396
1411
  }
1397
1412
 
1413
+ /**
1414
+ * Time navigator (ARCHITECTURE.md §8) — the hover-revealed zoom / step controls
1415
+ * that sit just above the time axis: `−` `+` to zoom, `‹` `›` to step one bar.
1416
+ *
1417
+ * Invisible until the pointer nears the bottom of the chart, so a clean chart
1418
+ * stays clean. It fades in and out rather than snapping, which is what keeps it
1419
+ * from reading as a glitch when the cursor crosses the reveal band.
1420
+ *
1421
+ * Reveal is driven by an explicit `setPointer` from the chart, **not** by
1422
+ * `rc.hoverId`. Hover ids come from `bestHit`, which picks the nearest primitive
1423
+ * — so a drawing or an order line near the bottom of the chart would win the
1424
+ * hit and silently hide the controls. Pointer position is the honest input here;
1425
+ * hit-testing still owns the buttons themselves.
1426
+ */
1427
+
1428
+ /** Command each button runs. These are `Chart` shortcut command ids. */
1429
+ type TimeNavigatorAction = 'zoomOut' | 'zoomIn' | 'panLeftBar' | 'panRightBar';
1430
+ interface TimeNavigatorOptions {
1431
+ /** Prefix for hit ids. Lets a host run more than one. */
1432
+ id: string;
1433
+ /** Buttons, left to right. A `null` inserts a gap between groups. */
1434
+ buttons: readonly (TimeNavigatorAction | null)[];
1435
+ /** Button box size in media px. */
1436
+ size: number;
1437
+ /** Gap between buttons, and the wider gap a `null` produces. */
1438
+ gap: number;
1439
+ groupGap: number;
1440
+ /** Distance from the bottom of the plot to the bottom of the buttons. */
1441
+ bottomMargin: number;
1442
+ /**
1443
+ * Height of the reveal band above the plot bottom. The pointer anywhere in
1444
+ * this band brings the controls in.
1445
+ */
1446
+ revealHeight: number;
1447
+ /** Seconds the fade takes. 0 disables the animation. */
1448
+ fadeSeconds: number;
1449
+ /** Tooltip label per action. */
1450
+ labels: Record<TimeNavigatorAction, string>;
1451
+ /** Optional keyboard hint shown next to the label, e.g. `"Ctrl + −"`. */
1452
+ hints: Partial<Record<TimeNavigatorAction, string>>;
1453
+ /** Show the tooltip above the hovered button. */
1454
+ showTooltip: boolean;
1455
+ font: number;
1456
+ radius: number;
1457
+ zOrder: ZOrder;
1458
+ }
1459
+
1398
1460
  /**
1399
1461
  * Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
1400
1462
  * DataLayer + time scale, the panes, the invalidate mask, and the render loop.
@@ -1455,6 +1517,12 @@ interface ChartOptions {
1455
1517
  * `(s) => new Date(s * 1000).toISOString().slice(11, 16)`.
1456
1518
  */
1457
1519
  timeFormatter?: (utcSeconds: number, tickMark?: TickMarkType) => string;
1520
+ /**
1521
+ * Hover-revealed zoom / step controls above the time axis (TradingView-style).
1522
+ * `true` by default — they stay invisible until the pointer nears the bottom
1523
+ * of the chart. Pass `false` to drop them, or an options object to restyle.
1524
+ */
1525
+ timeNavigator?: boolean | Partial<TimeNavigatorOptions>;
1458
1526
  }
1459
1527
  interface AddSeriesOptions {
1460
1528
  /** Target pane index (0 = price). Higher panes are created on demand. */
@@ -1565,6 +1633,8 @@ declare class Chart {
1565
1633
  private _clickCb;
1566
1634
  private _crosshairCb;
1567
1635
  private _pointerMoved;
1636
+ /** While true, pointer gestures place anchors instead of panning. */
1637
+ private _placementMode;
1568
1638
  private _downPane;
1569
1639
  private _downX;
1570
1640
  private _downLocalY;
@@ -1588,6 +1658,9 @@ declare class Chart {
1588
1658
  private _priceScaleOptions;
1589
1659
  private _timeFormatter;
1590
1660
  private _leftAxisWidth;
1661
+ private _timeNav;
1662
+ /** Pane the navigator is currently attached to, so it can follow the bottom. */
1663
+ private _timeNavPane;
1591
1664
  constructor(container: HTMLElement, options?: ChartOptions);
1592
1665
  /** Register a callback fired when the user pans near the left (oldest) edge. */
1593
1666
  setHistoryLoader(loader: () => void): void;
@@ -1755,6 +1828,14 @@ declare class Chart {
1755
1828
  * at runtime. Pass undefined to restore the IST default.
1756
1829
  */
1757
1830
  setTimeFormatter(fn: ((utcSeconds: number, tickMark?: TickMarkType) => string) | undefined): void;
1831
+ /**
1832
+ * Turn pointer gestures into anchor placement instead of panning. A host arms
1833
+ * this while a drawing tool is active: a press no longer scrolls the chart, and
1834
+ * a press-drag-release is reported as two `click` events (press point, then
1835
+ * release point, the latter tagged `viaDrag`) so a two-point shape can be drawn
1836
+ * in one gesture. `DrawingController` drives this for you.
1837
+ */
1838
+ setPlacementMode(active: boolean): void;
1758
1839
  /** Swap the palette at runtime (dark/light toggle) without recreating the chart. */
1759
1840
  setTheme(theme: ChartTheme): void;
1760
1841
  /**
@@ -1852,6 +1933,22 @@ declare class Chart {
1852
1933
  private _handleLegendAction;
1853
1934
  /** Cumulative top + height of each pane, by weight (the source of truth for hit-testing). */
1854
1935
  private _paneLayout;
1936
+ /**
1937
+ * Keyboard hints for the navigator tooltips, read from the live keymap so a
1938
+ * rebind shows up in the tooltip instead of a stale hardcoded string. The
1939
+ * one-bar step buttons have no default binding, so they get no hint.
1940
+ */
1941
+ private _navHints;
1942
+ /**
1943
+ * Keep the navigator on the bottom pane — it belongs just above the time
1944
+ * axis, and adding or removing a pane moves which one that is.
1945
+ */
1946
+ private _syncTimeNavPane;
1947
+ /**
1948
+ * Push the pointer to the navigator and keep painting while it fades, so the
1949
+ * animation runs even when nothing else on the chart is changing.
1950
+ */
1951
+ private _feedTimeNav;
1855
1952
  private _renderContext;
1856
1953
  private _observeSize;
1857
1954
  private _onFrame;
@@ -1971,6 +2068,11 @@ declare class DrawingController {
1971
2068
  constructor(chart: Chart, options?: DrawingControllerOptions);
1972
2069
  /** Arm a tool for placement, or pass null to return to the cursor. */
1973
2070
  setTool(toolId: string | null): void;
2071
+ /**
2072
+ * Ask the chart to stop panning and report gestures as anchor placement.
2073
+ * Guarded so a base bundle predating `setPlacementMode` still loads the tier.
2074
+ */
2075
+ private _setPlacementMode;
1974
2076
  activeTool(): string | null;
1975
2077
  setOptions(patch: DrawingControllerOptions): void;
1976
2078
  /** Every drawing, in creation order. */
package/dist/index.d.ts CHANGED
@@ -707,6 +707,8 @@ declare class Pane {
707
707
  /** Remove a series record if present; returns true if it was found. */
708
708
  removeSeries(record: SeriesRecord): boolean;
709
709
  series(): readonly SeriesRecord[];
710
+ /** Primitives attached to this pane, in draw order. */
711
+ primitives(): readonly IPrimitive[];
710
712
  addPrimitive(primitive: IPrimitive, host: PrimitiveHost): void;
711
713
  /** Remove a primitive if present; returns true if it was found. */
712
714
  removePrimitive(primitive: IPrimitive): boolean;
@@ -1532,6 +1534,98 @@ declare class EventMarkers implements IPrimitive {
1532
1534
  hitTest(x: number, y: number): PrimitiveHit | null;
1533
1535
  }
1534
1536
 
1537
+ /**
1538
+ * Time navigator (ARCHITECTURE.md §8) — the hover-revealed zoom / step controls
1539
+ * that sit just above the time axis: `−` `+` to zoom, `‹` `›` to step one bar.
1540
+ *
1541
+ * Invisible until the pointer nears the bottom of the chart, so a clean chart
1542
+ * stays clean. It fades in and out rather than snapping, which is what keeps it
1543
+ * from reading as a glitch when the cursor crosses the reveal band.
1544
+ *
1545
+ * Reveal is driven by an explicit `setPointer` from the chart, **not** by
1546
+ * `rc.hoverId`. Hover ids come from `bestHit`, which picks the nearest primitive
1547
+ * — so a drawing or an order line near the bottom of the chart would win the
1548
+ * hit and silently hide the controls. Pointer position is the honest input here;
1549
+ * hit-testing still owns the buttons themselves.
1550
+ */
1551
+
1552
+ /** Command each button runs. These are `Chart` shortcut command ids. */
1553
+ type TimeNavigatorAction = 'zoomOut' | 'zoomIn' | 'panLeftBar' | 'panRightBar';
1554
+ interface TimeNavigatorOptions {
1555
+ /** Prefix for hit ids. Lets a host run more than one. */
1556
+ id: string;
1557
+ /** Buttons, left to right. A `null` inserts a gap between groups. */
1558
+ buttons: readonly (TimeNavigatorAction | null)[];
1559
+ /** Button box size in media px. */
1560
+ size: number;
1561
+ /** Gap between buttons, and the wider gap a `null` produces. */
1562
+ gap: number;
1563
+ groupGap: number;
1564
+ /** Distance from the bottom of the plot to the bottom of the buttons. */
1565
+ bottomMargin: number;
1566
+ /**
1567
+ * Height of the reveal band above the plot bottom. The pointer anywhere in
1568
+ * this band brings the controls in.
1569
+ */
1570
+ revealHeight: number;
1571
+ /** Seconds the fade takes. 0 disables the animation. */
1572
+ fadeSeconds: number;
1573
+ /** Tooltip label per action. */
1574
+ labels: Record<TimeNavigatorAction, string>;
1575
+ /** Optional keyboard hint shown next to the label, e.g. `"Ctrl + −"`. */
1576
+ hints: Partial<Record<TimeNavigatorAction, string>>;
1577
+ /** Show the tooltip above the hovered button. */
1578
+ showTooltip: boolean;
1579
+ font: number;
1580
+ radius: number;
1581
+ zOrder: ZOrder;
1582
+ }
1583
+ declare const DEFAULT_TIME_NAVIGATOR_OPTIONS: TimeNavigatorOptions;
1584
+ declare class TimeNavigator implements IPrimitive {
1585
+ private _opts;
1586
+ private _host;
1587
+ /** Button geometry from the last paint, in media px relative to the plot. */
1588
+ private _boxes;
1589
+ /** Pointer in plot-local media px, or null when it left the pane. */
1590
+ private _pointer;
1591
+ /** 0 hidden, 1 fully shown. Eased toward the target each frame. */
1592
+ private _opacity;
1593
+ private _lastFrameMs;
1594
+ private _now;
1595
+ constructor(opts?: Partial<TimeNavigatorOptions>, now?: () => number);
1596
+ attached(host: PrimitiveHost): void;
1597
+ detached(): void;
1598
+ zOrder(): ZOrder;
1599
+ options(): TimeNavigatorOptions;
1600
+ setOptions(patch: Partial<TimeNavigatorOptions>): void;
1601
+ /**
1602
+ * Tell the navigator where the pointer is, in plot-local media px. `null`
1603
+ * when it leaves. The chart calls this; hosts driving their own navigator
1604
+ * should too.
1605
+ */
1606
+ setPointer(p: {
1607
+ x: number;
1608
+ y: number;
1609
+ } | null): void;
1610
+ /** True when the pointer is inside the reveal band. */
1611
+ private _revealed;
1612
+ private _targetOpacity;
1613
+ /** Top of the reveal band, recomputed each paint from the plot height. */
1614
+ private _revealTop;
1615
+ /** Whether the fade is still running — the chart keeps painting while true. */
1616
+ animating(): boolean;
1617
+ draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
1618
+ /** Which button the pointer is over, or null. */
1619
+ private _hoveredAction;
1620
+ private _button;
1621
+ private _tooltip;
1622
+ /**
1623
+ * Buttons hit-test only while visible, so a hidden navigator never steals a
1624
+ * click from the chart body underneath it.
1625
+ */
1626
+ hitTest(x: number, y: number): PrimitiveHit | null;
1627
+ }
1628
+
1535
1629
  /**
1536
1630
  * Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
1537
1631
  * DataLayer + time scale, the panes, the invalidate mask, and the render loop.
@@ -1592,6 +1686,12 @@ interface ChartOptions {
1592
1686
  * `(s) => new Date(s * 1000).toISOString().slice(11, 16)`.
1593
1687
  */
1594
1688
  timeFormatter?: (utcSeconds: number, tickMark?: TickMarkType) => string;
1689
+ /**
1690
+ * Hover-revealed zoom / step controls above the time axis (TradingView-style).
1691
+ * `true` by default — they stay invisible until the pointer nears the bottom
1692
+ * of the chart. Pass `false` to drop them, or an options object to restyle.
1693
+ */
1694
+ timeNavigator?: boolean | Partial<TimeNavigatorOptions>;
1595
1695
  }
1596
1696
  interface AddSeriesOptions {
1597
1697
  /** Target pane index (0 = price). Higher panes are created on demand. */
@@ -1704,6 +1804,8 @@ declare class Chart {
1704
1804
  private _clickCb;
1705
1805
  private _crosshairCb;
1706
1806
  private _pointerMoved;
1807
+ /** While true, pointer gestures place anchors instead of panning. */
1808
+ private _placementMode;
1707
1809
  private _downPane;
1708
1810
  private _downX;
1709
1811
  private _downLocalY;
@@ -1727,6 +1829,9 @@ declare class Chart {
1727
1829
  private _priceScaleOptions;
1728
1830
  private _timeFormatter;
1729
1831
  private _leftAxisWidth;
1832
+ private _timeNav;
1833
+ /** Pane the navigator is currently attached to, so it can follow the bottom. */
1834
+ private _timeNavPane;
1730
1835
  constructor(container: HTMLElement, options?: ChartOptions);
1731
1836
  /** Register a callback fired when the user pans near the left (oldest) edge. */
1732
1837
  setHistoryLoader(loader: () => void): void;
@@ -1894,6 +1999,14 @@ declare class Chart {
1894
1999
  * at runtime. Pass undefined to restore the IST default.
1895
2000
  */
1896
2001
  setTimeFormatter(fn: ((utcSeconds: number, tickMark?: TickMarkType) => string) | undefined): void;
2002
+ /**
2003
+ * Turn pointer gestures into anchor placement instead of panning. A host arms
2004
+ * this while a drawing tool is active: a press no longer scrolls the chart, and
2005
+ * a press-drag-release is reported as two `click` events (press point, then
2006
+ * release point, the latter tagged `viaDrag`) so a two-point shape can be drawn
2007
+ * in one gesture. `DrawingController` drives this for you.
2008
+ */
2009
+ setPlacementMode(active: boolean): void;
1897
2010
  /** Swap the palette at runtime (dark/light toggle) without recreating the chart. */
1898
2011
  setTheme(theme: ChartTheme): void;
1899
2012
  /**
@@ -1991,6 +2104,22 @@ declare class Chart {
1991
2104
  private _handleLegendAction;
1992
2105
  /** Cumulative top + height of each pane, by weight (the source of truth for hit-testing). */
1993
2106
  private _paneLayout;
2107
+ /**
2108
+ * Keyboard hints for the navigator tooltips, read from the live keymap so a
2109
+ * rebind shows up in the tooltip instead of a stale hardcoded string. The
2110
+ * one-bar step buttons have no default binding, so they get no hint.
2111
+ */
2112
+ private _navHints;
2113
+ /**
2114
+ * Keep the navigator on the bottom pane — it belongs just above the time
2115
+ * axis, and adding or removing a pane moves which one that is.
2116
+ */
2117
+ private _syncTimeNavPane;
2118
+ /**
2119
+ * Push the pointer to the navigator and keep painting while it fades, so the
2120
+ * animation runs even when nothing else on the chart is changing.
2121
+ */
2122
+ private _feedTimeNav;
1994
2123
  private _renderContext;
1995
2124
  private _observeSize;
1996
2125
  private _onFrame;
@@ -2954,4 +3083,4 @@ declare function lerp(a: number, b: number, t: number): number;
2954
3083
  */
2955
3084
  declare function roundToTick(value: number, step: number): number;
2956
3085
 
2957
- export { ALT_PRESET, type AddSeriesOptions, type AggTick, BUILTIN_COMMANDS, type Bar, type BarUpdate, type BarsRequest, BuySellButtons, type BuySellButtonsOptions, CHART_STATE_VERSION, CandleBuilder, type CandleBuilderOptions, type CandleStyle, type CandleUpdate, Chart, type ChartEvent, type ChartOptions, type ChartState, type ChartTheme, type CrosshairMoveEvent, type CustomShortcut, DEFAULT_CANDLE_BUILDER_OPTIONS, DEFAULT_CANDLE_STYLE, DEFAULT_HISTOGRAM_STYLE, DEFAULT_KEYMAP, DEFAULT_PRICE_SCALE_OPTIONS, DEFAULT_THEME, DEFAULT_TIME_SCALE_OPTIONS, DEFAULT_TRADING_COLORS, type DataFeed, type DepthLevel, type DrawItem, EventMarkers, FakeDataFeed, type FeedScheduler, type HistogramStyle, INDICATOR_LINE_STYLES, INDICATOR_SOURCES, type IPrimitive, IST_OFFSET_SECONDS, type IndicatorApi, type IndicatorAttachContext, type IndicatorDescriptor, type IndicatorHost, type IndicatorInput, type IndicatorLevel, type IndicatorPlot, type IndicatorSettings, type IndicatorSource, type IndicatorState, type IndicatorStore, type IndicatorValues, InvalidationLevel, type KeymapEntry, type LateTickPolicy, type LegendValue, type LinePoint, type LogicalRange, LogoWatermark, type LogoWatermarkOptions, type LtpEvent, type MarkerPosition, type MarkerShape, type MarkerSize, type MarketDepth, type OpenAlgoConfig, OpenAlgoDataFeed, type OpenAlgoLiveConfig, OpenAlgoLiveDataFeed, type OpenAlgoTradeConfig, OpenAlgoTradeFeed, type OpenAlgoWsConfig, OpenAlgoWsFeed, type OrderSide$1 as OrderSide, type OrderType$1 as OrderType, type OriginalTime, Pane, type PaneInvalidation, PaneLegend, type PaneLegendAction, type PaneLegendOptions, type PaneState, type PlaceOrder, type PositionSide, PriceLine, type PriceLineOptions, type PriceRange, PriceScale, type PriceScaleId, type PriceScaleMode, type PriceScaleOptions, type PriceScaleState, type PrimitiveHit, type PrimitiveHost, type PrimitiveRenderContext, type RendererEntry, type RestoreReport, type SeriesApi, type SeriesDataItem, type SeriesMarker, SeriesMarkers, type SeriesRenderContext, type SeriesState, type SeriesStyle, type SeriesType, type ShortcutListItem, ShortcutManager, type ShortcutManagerOptions, type ShortcutPreset, type ShortcutScope, type ShortcutTriggerEvent, type Size, type SocketFactory, type SocketLike, type SupertrendPoint, type Tick, TickBarAggregator, type TickMarkType, type TickTimeframe, TimeScale, type TimeScaleOp, type TimeScaleOptions, type TradeFeed, type TradeMarkerVariant, TradeMarkersPrimitive, type TradingColors, TradingController, type TradingHost, type TradingLineStyle, type TradingLineVariant, type TradingOrder, type TradingOrderSide, type TradingOrderType, type TradingPosition, type TradingSettings, type TradingSyncPayload, type TradingTrade, type UTCSeconds, type UnsubscribeFn, VERSION, type VolumeMode, type WatermarkPosition, type Whitespace, type WsControlMessage, type WsMode, type WsState, type ZOrder, atr, autoscaleRange, bestHit, bitmapSize, clamp, compactVolume, conflateBars, conflateItems, conflationGroupSize, createChart, darkTheme, drawShape, effectiveMarkerPx, ema, emaSeries, epochMsToUtcSeconds, eventToCombo, formatCombo, formatIstDate, formatIstTime, formatIstTimeSeconds, formatSubscribe, formatUnsubscribe, generateBars, getChartType, getIndicator, hasIndicator, indicatorDefaults, indicatorStyleInputs, intervalToSeconds, isNewIstDay, isReservedCombo, isValidCombo, isWhitespace, istStringToUtcSeconds, lerp, lightTheme, mapHistoryResponse, mapOrder, mapPosition, markerSizePx, mergeBars, niceTicks, normalizeCombo, optimalBarWidth, parseCombo, parseMessage, plotStyleKeys, precisionForStep, registerChartType, registerIndicator, registeredChartTypes, registeredIndicators, roundToTick, rowTimeToUtcSeconds, rsi, rsiSeries, snapToDevicePixel, sourceValue, sourceValues, supertrend, supertrendSeries, toBar, trueRange, utcSecondsToIstDateString, utcSecondsToIstParts, version, verticalGradient, watermarkRect };
3086
+ export { ALT_PRESET, type AddSeriesOptions, type AggTick, BUILTIN_COMMANDS, type Bar, type BarUpdate, type BarsRequest, BuySellButtons, type BuySellButtonsOptions, CHART_STATE_VERSION, CandleBuilder, type CandleBuilderOptions, type CandleStyle, type CandleUpdate, Chart, type ChartEvent, type ChartOptions, type ChartState, type ChartTheme, type CrosshairMoveEvent, type CustomShortcut, DEFAULT_CANDLE_BUILDER_OPTIONS, DEFAULT_CANDLE_STYLE, DEFAULT_HISTOGRAM_STYLE, DEFAULT_KEYMAP, DEFAULT_PRICE_SCALE_OPTIONS, DEFAULT_THEME, DEFAULT_TIME_NAVIGATOR_OPTIONS, DEFAULT_TIME_SCALE_OPTIONS, DEFAULT_TRADING_COLORS, type DataFeed, type DepthLevel, type DrawItem, EventMarkers, FakeDataFeed, type FeedScheduler, type HistogramStyle, INDICATOR_LINE_STYLES, INDICATOR_SOURCES, type IPrimitive, IST_OFFSET_SECONDS, type IndicatorApi, type IndicatorAttachContext, type IndicatorDescriptor, type IndicatorHost, type IndicatorInput, type IndicatorLevel, type IndicatorPlot, type IndicatorSettings, type IndicatorSource, type IndicatorState, type IndicatorStore, type IndicatorValues, InvalidationLevel, type KeymapEntry, type LateTickPolicy, type LegendValue, type LinePoint, type LogicalRange, LogoWatermark, type LogoWatermarkOptions, type LtpEvent, type MarkerPosition, type MarkerShape, type MarkerSize, type MarketDepth, type OpenAlgoConfig, OpenAlgoDataFeed, type OpenAlgoLiveConfig, OpenAlgoLiveDataFeed, type OpenAlgoTradeConfig, OpenAlgoTradeFeed, type OpenAlgoWsConfig, OpenAlgoWsFeed, type OrderSide$1 as OrderSide, type OrderType$1 as OrderType, type OriginalTime, Pane, type PaneInvalidation, PaneLegend, type PaneLegendAction, type PaneLegendOptions, type PaneState, type PlaceOrder, type PositionSide, PriceLine, type PriceLineOptions, type PriceRange, PriceScale, type PriceScaleId, type PriceScaleMode, type PriceScaleOptions, type PriceScaleState, type PrimitiveHit, type PrimitiveHost, type PrimitiveRenderContext, type RendererEntry, type RestoreReport, type SeriesApi, type SeriesDataItem, type SeriesMarker, SeriesMarkers, type SeriesRenderContext, type SeriesState, type SeriesStyle, type SeriesType, type ShortcutListItem, ShortcutManager, type ShortcutManagerOptions, type ShortcutPreset, type ShortcutScope, type ShortcutTriggerEvent, type Size, type SocketFactory, type SocketLike, type SupertrendPoint, type Tick, TickBarAggregator, type TickMarkType, type TickTimeframe, TimeNavigator, type TimeNavigatorAction, type TimeNavigatorOptions, TimeScale, type TimeScaleOp, type TimeScaleOptions, type TradeFeed, type TradeMarkerVariant, TradeMarkersPrimitive, type TradingColors, TradingController, type TradingHost, type TradingLineStyle, type TradingLineVariant, type TradingOrder, type TradingOrderSide, type TradingOrderType, type TradingPosition, type TradingSettings, type TradingSyncPayload, type TradingTrade, type UTCSeconds, type UnsubscribeFn, VERSION, type VolumeMode, type WatermarkPosition, type Whitespace, type WsControlMessage, type WsMode, type WsState, type ZOrder, atr, autoscaleRange, bestHit, bitmapSize, clamp, compactVolume, conflateBars, conflateItems, conflationGroupSize, createChart, darkTheme, drawShape, effectiveMarkerPx, ema, emaSeries, epochMsToUtcSeconds, eventToCombo, formatCombo, formatIstDate, formatIstTime, formatIstTimeSeconds, formatSubscribe, formatUnsubscribe, generateBars, getChartType, getIndicator, hasIndicator, indicatorDefaults, indicatorStyleInputs, intervalToSeconds, isNewIstDay, isReservedCombo, isValidCombo, isWhitespace, istStringToUtcSeconds, lerp, lightTheme, mapHistoryResponse, mapOrder, mapPosition, markerSizePx, mergeBars, niceTicks, normalizeCombo, optimalBarWidth, parseCombo, parseMessage, plotStyleKeys, precisionForStep, registerChartType, registerIndicator, registeredChartTypes, registeredIndicators, roundToTick, rowTimeToUtcSeconds, rsi, rsiSeries, snapToDevicePixel, sourceValue, sourceValues, supertrend, supertrendSeries, toBar, trueRange, utcSecondsToIstDateString, utcSecondsToIstParts, version, verticalGradient, watermarkRect };