acttrader-charts 1.2.0-beta.4 → 1.2.0-beta.5

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
@@ -312,6 +312,34 @@ When the on-canvas ✓/✗ buttons are hidden (mobile native UI), the chart adap
312
312
 
313
313
  When `enableTrading` is on and live BID/ASK data is streaming, hovering / activating the trade crosshair button while the cursor price is inside the spread shows **"Buy Market"** and **"Sell Market"** rows instead of the standard Limit/Stop rows. Tapping either row calls `showMarketDraft()` internally and emits `draftInitiated` with `orderType: 'market'`.
314
314
 
315
+ ### Horizontal (time-axis) order-line dragging
316
+
317
+ Opt-in via `features.orderLineTimeDrag` (off by default; enable it per broker from the host app — e.g. only for Hankotrade users). When enabled, any level flagged `timeDraggable: true` can have its **info-box badge** dragged left/right to re-anchor the order to a different candle. The **price line stays locked** — only the time anchor moves. Grab the badge for horizontal drag (`grab` / `grabbing` cursor); the price line itself still drags vertically as before.
318
+
319
+ ```ts
320
+ const chart = new ChartEngine({
321
+ container,
322
+ features: { orderLineTimeDrag: true }, // host enables this only for the gated broker
323
+ orderLineDragSnap: true, // snap to nearest candle on release (default)
324
+ });
325
+
326
+ chart.setLevels(
327
+ [{ id: 'A1', price: 1.21013, side: 'buy', orderType: 'limit', lots: 0.08,
328
+ timestamp: 1718000000000, timeDraggable: true }],
329
+ 'id', 'price', 'pending',
330
+ );
331
+
332
+ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
333
+ // Persist the move, then echo `timestamp: toTimestamp` in your next setLevels().
334
+ });
335
+ ```
336
+
337
+ - **Bounds:** the badge is clamped to the visible viewport — it can't be dragged past the left/right edge.
338
+ - **Snap:** controlled by `orderLineDragSnap` (default `true`); set `false` to keep the exact released time.
339
+ - **Escape / touch-cancel:** reverts the badge to its starting candle without emitting `orderLineMoved`.
340
+ - **Stays put after release:** the chart holds the dropped position across `setLevels` refreshes until you echo the new `timestamp` back (auto-released on match).
341
+ - A level **without** `timestamp` renders exactly as before (badge centered), so existing consumers are unaffected.
342
+
315
343
  ---
316
344
 
317
345
  ## Default Configuration
@@ -368,6 +396,8 @@ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activa
368
396
  | `showTradeLevelsAlways` | | `false` | Always render SL/TP bracket lines + price pills, even when the parent level is not hovered or selected. The close (×) button stays hover-only so the chart isn't cluttered. Toggleable from the Settings dialog (Trading tab). Persisted in `localStorage`. |
369
397
  | `tradeLevelButtonScale` | | `1` | Multiplier for trade-level Confirm/Cancel/Edit/Close button radii and gaps. Scales visuals **and** hit/drag areas together — raise it on touch devices for larger tap targets. Clamped to `[1, 3]`. Also settable at runtime via `chart.setTradeLevelButtonScale(scale)` |
370
398
  | `tfcEnabled` | | `true` | Enable the TFC toggle button in the top bar. When `false`, TFC is completely disabled — the toggle button is hidden and all trade levels, draft orders, and the floating trade button are suppressed |
399
+ | `features.orderLineTimeDrag` | | `false` | Enable **horizontal (time-axis) order-line dragging**. A level with `timeDraggable: true` can have its info-box badge dragged left/right to re-anchor the order to a different candle — **price stays locked**. Emits `orderLineMoved` on release. Off by default; intended to be enabled per broker (e.g. Hankotrade) by the host app |
400
+ | `orderLineDragSnap` | | `true` | When horizontal dragging is enabled, snap the badge to the nearest candle on release. Set `false` to keep the exact released time |
371
401
  | `levelClusteringEnabled` | | `true` | Enable trade-level fan-out clustering; overlapping levels group into expandable badges |
372
402
  | `clusterThresholdDistance` | | `20` | Pixel proximity threshold for clustering (only when `levelClusteringEnabled` is `true`) |
373
403
  | `hideSymbolAndTick` | | `false` | Hide the symbol name and tick-activity (streaming) dot in the top-left overlay. Does **not** affect the OHLC(V) strip — use `hideOHLCV` for that |
@@ -450,6 +480,16 @@ new ChartEngine({
450
480
  });
451
481
  ```
452
482
 
483
+ > **Fonts & the host document.** Canvas-drawn UI text (axes, crosshair, indicator pills)
484
+ > uses the `*FontFamily` values above. The DOM overlays — the **symbol name**, the
485
+ > **O/H/L/C strip**, and the toolbar — use `font-family: inherit`, so they resolve to the
486
+ > **host document's `body` font**. When you mount the chart on a normal web page this lets
487
+ > the chart pick up your site's font automatically. When you embed it in a bare host (e.g.
488
+ > a native WebView whose page sets no font), give the host `<body>` a `font-family` — the
489
+ > bundled WebView template (`wrappers/webview/src/template.html`) now ships one
490
+ > (`'Inter', system-ui, -apple-system, …`) so these elements fall back to the platform
491
+ > system font instead of the WebView's default serif.
492
+
453
493
  You can also import individual section defaults:
454
494
 
455
495
  ```ts
@@ -893,6 +933,15 @@ chart.on('tfcToggle', ({ enabled }) => {}); // TFC toggled on or off via
893
933
  chart.on('tradeLevelDragEnd', ({ label, type, newPrice, data }) => {}); // deprecated — use tradeLevelEdit
894
934
  chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}); // deprecated
895
935
 
936
+ // Horizontal (time-axis) order-line dragging — requires features.orderLineTimeDrag + level.timeDraggable.
937
+ // Price is never changed; only the badge's time anchor moves. `label` is your order id.
938
+ chart.on('orderLineMoveStart', ({ label, fromTimestamp, fromBarIndex, isFullscreen }) => {});
939
+ chart.on('orderLineMoving', ({ label, toTimestamp, toBarIndex, isFullscreen }) => {}); // fires on every move
940
+ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, fromBarIndex, toBarIndex, data, isFullscreen }) => {
941
+ // Persist the new time anchor for this order. Echo `timestamp: toTimestamp` back in your
942
+ // next setLevels() payload so the badge stays put across refreshes.
943
+ });
944
+
896
945
  // Fires after addLevelBracket() auto-places a bracket, delivering the computed price back to the caller
897
946
  chart.on('tradeLevelBracketActivated', ({ label, bracketType, price, isFullscreen }) => {
898
947
  // Use price to pre-populate the SL/TP input field in your native form
@@ -1020,8 +1020,19 @@ interface ChartConfig {
1020
1020
  *
1021
1021
  * If both `headerLayout` and the deprecated `features.advancedToolbar` are set,
1022
1022
  * `headerLayout` wins.
1023
+ *
1024
+ * - `'mobile'` — Mobile header: a single scrollable action row
1025
+ * (`Tools` button · timeframe pills · `Ask AI` button). Opt-in and fully
1026
+ * isolated; selecting it has no effect on any other white-label. The host
1027
+ * gates it itself, e.g. `headerLayout: isMobile ? 'mobile' : undefined`.
1028
+ * The `Ask AI` button only renders when {@link ChartConfig.onAskAiClick} is set.
1029
+ */
1030
+ headerLayout?: 'simple' | 'advanced' | 'compact' | 'mobile';
1031
+ /**
1032
+ * Called when the user taps the "Ask AI" (✦) button in the `'mobile'` header.
1033
+ * Omit to hide the button entirely. No effect in other header layouts.
1023
1034
  */
1024
- headerLayout?: 'simple' | 'advanced' | 'compact';
1035
+ onAskAiClick?: () => void;
1025
1036
  /**
1026
1037
  * Hide the chart header entirely (simple TopBar / AdvancedToolbar /
1027
1038
  * CompactToolbar — whichever `headerLayout` would have rendered).
@@ -1078,6 +1089,15 @@ interface ChartConfig {
1078
1089
  * removed in a future major version. Currently treated as an alias.
1079
1090
  */
1080
1091
  advancedToolbar?: boolean;
1092
+ /**
1093
+ * Enable horizontal (time-axis) order-line dragging: a level whose `timeDraggable`
1094
+ * is true can have its info-box badge dragged left/right to re-anchor the order to
1095
+ * a different candle (price stays locked), emitting `orderLineMoved` on release.
1096
+ * This is the broker-gating seam — hosts (e.g. the Hankotrade app) enable it only
1097
+ * for their flagged users. When `false` / omitted, behavior is unchanged.
1098
+ * Default: false.
1099
+ */
1100
+ orderLineTimeDrag?: boolean;
1081
1101
  };
1082
1102
  /**
1083
1103
  * Fetches historical OHLC bars for a compare symbol. When provided, the
@@ -1141,6 +1161,12 @@ interface ChartConfig {
1141
1161
  * allowing the user to enable/disable TFC at runtime.
1142
1162
  */
1143
1163
  tfcEnabled?: boolean;
1164
+ /**
1165
+ * Snap a horizontally-dragged order line to the nearest candle on drag release.
1166
+ * Only relevant when `features.orderLineTimeDrag` is enabled. When `false`, the badge
1167
+ * keeps the exact (interpolated) time it was released at. Default: `true`.
1168
+ */
1169
+ orderLineDragSnap?: boolean;
1144
1170
  }
1145
1171
  interface IndicatorResult {
1146
1172
  index: number;
@@ -1543,6 +1569,33 @@ type ChartEventMap = {
1543
1569
  bracketOrderLabel?: string;
1544
1570
  }>;
1545
1571
  };
1572
+ /** Emitted at the instant a horizontal (time-axis) order-line drag begins — before any movement.
1573
+ * Only fires when `features.orderLineTimeDrag` is enabled and the level is `timeDraggable`. */
1574
+ orderLineMoveStart: {
1575
+ label: string;
1576
+ fromTimestamp: number;
1577
+ fromBarIndex: number;
1578
+ isFullscreen: boolean;
1579
+ };
1580
+ /** Emitted on every move during a horizontal order-line drag (before release) for live external sync. */
1581
+ orderLineMoving: {
1582
+ label: string;
1583
+ toTimestamp: number;
1584
+ toBarIndex: number;
1585
+ isFullscreen: boolean;
1586
+ };
1587
+ /** Emitted once when a horizontal order-line drag ends (after snap, if enabled).
1588
+ * `label` is the level's label (i.e. your order id). The price is unchanged — only the
1589
+ * time anchor moved. `data` is the level's original object, returned as-is. */
1590
+ orderLineMoved: {
1591
+ label: string;
1592
+ fromTimestamp: number;
1593
+ toTimestamp: number;
1594
+ fromBarIndex: number;
1595
+ toBarIndex: number;
1596
+ data: unknown;
1597
+ isFullscreen: boolean;
1598
+ };
1546
1599
  /**
1547
1600
  * Emitted when the user picks a preset in the multi-layout popover or toggles
1548
1601
  * a sync option. Fires only when `enableMultipleLayouts: true`. The host
@@ -1677,6 +1730,19 @@ interface PositionLevel {
1677
1730
  orderType?: 'limit' | 'stop';
1678
1731
  /** Lot size for Entry Limit / Entry Stop orders — shown in the info box label. */
1679
1732
  lots?: number;
1733
+ /**
1734
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1735
+ * box is centered horizontally over the candle nearest this time instead of the chart
1736
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1737
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1738
+ */
1739
+ timestamp?: number;
1740
+ /**
1741
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1742
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1743
+ * Emits `orderLineMoved` on release. Default: false.
1744
+ */
1745
+ timeDraggable?: boolean;
1680
1746
  /**
1681
1747
  * Your original position object. Returned as-is in the `tradeLevelClose` event.
1682
1748
  * The library never inspects this value.
@@ -1721,6 +1787,19 @@ interface PendingOrderLevel {
1721
1787
  * using the parent's `side` field (buy: price below parent → SL, above → TP; sell: reversed).
1722
1788
  */
1723
1789
  ToClose?: string;
1790
+ /**
1791
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1792
+ * box is centered horizontally over the candle nearest this time instead of the chart
1793
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1794
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1795
+ */
1796
+ timestamp?: number;
1797
+ /**
1798
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1799
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1800
+ * Emits `orderLineMoved` on release. Default: false.
1801
+ */
1802
+ timeDraggable?: boolean;
1724
1803
  /** Your original order object. Returned as-is in events. The library never inspects this. */
1725
1804
  data?: unknown;
1726
1805
  }
@@ -1020,8 +1020,19 @@ interface ChartConfig {
1020
1020
  *
1021
1021
  * If both `headerLayout` and the deprecated `features.advancedToolbar` are set,
1022
1022
  * `headerLayout` wins.
1023
+ *
1024
+ * - `'mobile'` — Mobile header: a single scrollable action row
1025
+ * (`Tools` button · timeframe pills · `Ask AI` button). Opt-in and fully
1026
+ * isolated; selecting it has no effect on any other white-label. The host
1027
+ * gates it itself, e.g. `headerLayout: isMobile ? 'mobile' : undefined`.
1028
+ * The `Ask AI` button only renders when {@link ChartConfig.onAskAiClick} is set.
1029
+ */
1030
+ headerLayout?: 'simple' | 'advanced' | 'compact' | 'mobile';
1031
+ /**
1032
+ * Called when the user taps the "Ask AI" (✦) button in the `'mobile'` header.
1033
+ * Omit to hide the button entirely. No effect in other header layouts.
1023
1034
  */
1024
- headerLayout?: 'simple' | 'advanced' | 'compact';
1035
+ onAskAiClick?: () => void;
1025
1036
  /**
1026
1037
  * Hide the chart header entirely (simple TopBar / AdvancedToolbar /
1027
1038
  * CompactToolbar — whichever `headerLayout` would have rendered).
@@ -1078,6 +1089,15 @@ interface ChartConfig {
1078
1089
  * removed in a future major version. Currently treated as an alias.
1079
1090
  */
1080
1091
  advancedToolbar?: boolean;
1092
+ /**
1093
+ * Enable horizontal (time-axis) order-line dragging: a level whose `timeDraggable`
1094
+ * is true can have its info-box badge dragged left/right to re-anchor the order to
1095
+ * a different candle (price stays locked), emitting `orderLineMoved` on release.
1096
+ * This is the broker-gating seam — hosts (e.g. the Hankotrade app) enable it only
1097
+ * for their flagged users. When `false` / omitted, behavior is unchanged.
1098
+ * Default: false.
1099
+ */
1100
+ orderLineTimeDrag?: boolean;
1081
1101
  };
1082
1102
  /**
1083
1103
  * Fetches historical OHLC bars for a compare symbol. When provided, the
@@ -1141,6 +1161,12 @@ interface ChartConfig {
1141
1161
  * allowing the user to enable/disable TFC at runtime.
1142
1162
  */
1143
1163
  tfcEnabled?: boolean;
1164
+ /**
1165
+ * Snap a horizontally-dragged order line to the nearest candle on drag release.
1166
+ * Only relevant when `features.orderLineTimeDrag` is enabled. When `false`, the badge
1167
+ * keeps the exact (interpolated) time it was released at. Default: `true`.
1168
+ */
1169
+ orderLineDragSnap?: boolean;
1144
1170
  }
1145
1171
  interface IndicatorResult {
1146
1172
  index: number;
@@ -1543,6 +1569,33 @@ type ChartEventMap = {
1543
1569
  bracketOrderLabel?: string;
1544
1570
  }>;
1545
1571
  };
1572
+ /** Emitted at the instant a horizontal (time-axis) order-line drag begins — before any movement.
1573
+ * Only fires when `features.orderLineTimeDrag` is enabled and the level is `timeDraggable`. */
1574
+ orderLineMoveStart: {
1575
+ label: string;
1576
+ fromTimestamp: number;
1577
+ fromBarIndex: number;
1578
+ isFullscreen: boolean;
1579
+ };
1580
+ /** Emitted on every move during a horizontal order-line drag (before release) for live external sync. */
1581
+ orderLineMoving: {
1582
+ label: string;
1583
+ toTimestamp: number;
1584
+ toBarIndex: number;
1585
+ isFullscreen: boolean;
1586
+ };
1587
+ /** Emitted once when a horizontal order-line drag ends (after snap, if enabled).
1588
+ * `label` is the level's label (i.e. your order id). The price is unchanged — only the
1589
+ * time anchor moved. `data` is the level's original object, returned as-is. */
1590
+ orderLineMoved: {
1591
+ label: string;
1592
+ fromTimestamp: number;
1593
+ toTimestamp: number;
1594
+ fromBarIndex: number;
1595
+ toBarIndex: number;
1596
+ data: unknown;
1597
+ isFullscreen: boolean;
1598
+ };
1546
1599
  /**
1547
1600
  * Emitted when the user picks a preset in the multi-layout popover or toggles
1548
1601
  * a sync option. Fires only when `enableMultipleLayouts: true`. The host
@@ -1677,6 +1730,19 @@ interface PositionLevel {
1677
1730
  orderType?: 'limit' | 'stop';
1678
1731
  /** Lot size for Entry Limit / Entry Stop orders — shown in the info box label. */
1679
1732
  lots?: number;
1733
+ /**
1734
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1735
+ * box is centered horizontally over the candle nearest this time instead of the chart
1736
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1737
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1738
+ */
1739
+ timestamp?: number;
1740
+ /**
1741
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1742
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1743
+ * Emits `orderLineMoved` on release. Default: false.
1744
+ */
1745
+ timeDraggable?: boolean;
1680
1746
  /**
1681
1747
  * Your original position object. Returned as-is in the `tradeLevelClose` event.
1682
1748
  * The library never inspects this value.
@@ -1721,6 +1787,19 @@ interface PendingOrderLevel {
1721
1787
  * using the parent's `side` field (buy: price below parent → SL, above → TP; sell: reversed).
1722
1788
  */
1723
1789
  ToClose?: string;
1790
+ /**
1791
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1792
+ * box is centered horizontally over the candle nearest this time instead of the chart
1793
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1794
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1795
+ */
1796
+ timestamp?: number;
1797
+ /**
1798
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1799
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1800
+ * Emits `orderLineMoved` on release. Default: false.
1801
+ */
1802
+ timeDraggable?: boolean;
1724
1803
  /** Your original order object. Returned as-is in events. The library never inspects this. */
1725
1804
  data?: unknown;
1726
1805
  }