react-native-livechart 4.24.1 → 4.26.0

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.
Files changed (114) hide show
  1. package/dist/components/DegenParticlesOverlay.d.ts +2 -2
  2. package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
  3. package/dist/components/LiveChart.d.ts.map +1 -1
  4. package/dist/components/LiveChartSeries.d.ts.map +1 -1
  5. package/dist/components/LoadingOverlay.d.ts +5 -1
  6. package/dist/components/LoadingOverlay.d.ts.map +1 -1
  7. package/dist/components/YAxisOverlay.d.ts +3 -1
  8. package/dist/components/YAxisOverlay.d.ts.map +1 -1
  9. package/dist/constants.d.ts +3 -3
  10. package/dist/core/historyRangeCache.d.ts +25 -0
  11. package/dist/core/historyRangeCache.d.ts.map +1 -0
  12. package/dist/core/liveChartEngineTick.d.ts +6 -2
  13. package/dist/core/liveChartEngineTick.d.ts.map +1 -1
  14. package/dist/core/liveChartSeriesEngineTick.d.ts +2 -1
  15. package/dist/core/liveChartSeriesEngineTick.d.ts.map +1 -1
  16. package/dist/core/resolveConfig.d.ts +1 -1
  17. package/dist/core/useHistoryRevision.d.ts +5 -0
  18. package/dist/core/useHistoryRevision.d.ts.map +1 -0
  19. package/dist/core/useLiveChartEngine.d.ts +20 -2
  20. package/dist/core/useLiveChartEngine.d.ts.map +1 -1
  21. package/dist/core/useLiveChartSeriesEngine.d.ts +5 -1
  22. package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
  23. package/dist/draw/candleBodyPath.d.ts +10 -0
  24. package/dist/draw/candleBodyPath.d.ts.map +1 -0
  25. package/dist/draw/lineFillPaths.d.ts +10 -0
  26. package/dist/draw/lineFillPaths.d.ts.map +1 -0
  27. package/dist/draw/volume.d.ts +4 -1
  28. package/dist/draw/volume.d.ts.map +1 -1
  29. package/dist/draw/volumeRange.d.ts +12 -0
  30. package/dist/draw/volumeRange.d.ts.map +1 -0
  31. package/dist/hooks/crosshairShared.d.ts +8 -0
  32. package/dist/hooks/crosshairShared.d.ts.map +1 -1
  33. package/dist/hooks/useCandlePaths.d.ts +1 -1
  34. package/dist/hooks/useCandlePaths.d.ts.map +1 -1
  35. package/dist/hooks/useChartPaths.d.ts +1 -1
  36. package/dist/hooks/useChartPaths.d.ts.map +1 -1
  37. package/dist/hooks/useCrosshair.d.ts.map +1 -1
  38. package/dist/hooks/useDegen.d.ts +1 -0
  39. package/dist/hooks/useDegen.d.ts.map +1 -1
  40. package/dist/hooks/useDemandFrameLoop.d.ts +11 -0
  41. package/dist/hooks/useDemandFrameLoop.d.ts.map +1 -0
  42. package/dist/hooks/useLoadingLook.d.ts +12 -0
  43. package/dist/hooks/useLoadingLook.d.ts.map +1 -0
  44. package/dist/hooks/useMarkers.d.ts +3 -1
  45. package/dist/hooks/useMarkers.d.ts.map +1 -1
  46. package/dist/hooks/useMultiSeriesDegen.d.ts +1 -0
  47. package/dist/hooks/useMultiSeriesDegen.d.ts.map +1 -1
  48. package/dist/hooks/usePanScroll.d.ts +2 -0
  49. package/dist/hooks/usePanScroll.d.ts.map +1 -1
  50. package/dist/hooks/usePinchZoom.d.ts +2 -0
  51. package/dist/hooks/usePinchZoom.d.ts.map +1 -1
  52. package/dist/hooks/useReferenceDrag.d.ts +3 -2
  53. package/dist/hooks/useReferenceDrag.d.ts.map +1 -1
  54. package/dist/hooks/useReferenceLineGrouping.d.ts +19 -0
  55. package/dist/hooks/useReferenceLineGrouping.d.ts.map +1 -0
  56. package/dist/hooks/useVolumeRange.d.ts +14 -0
  57. package/dist/hooks/useVolumeRange.d.ts.map +1 -0
  58. package/dist/hooks/useXAxis.d.ts +7 -0
  59. package/dist/hooks/useXAxis.d.ts.map +1 -1
  60. package/dist/hooks/useYAxis.d.ts.map +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/math/rangeAnimation.d.ts +4 -0
  64. package/dist/math/rangeAnimation.d.ts.map +1 -0
  65. package/dist/math/referenceDrag.d.ts +17 -5
  66. package/dist/math/referenceDrag.d.ts.map +1 -1
  67. package/dist/math/referenceGroup.d.ts +2 -2
  68. package/dist/math/spline.d.ts +3 -1
  69. package/dist/math/spline.d.ts.map +1 -1
  70. package/dist/math/squiggly.d.ts +8 -0
  71. package/dist/math/squiggly.d.ts.map +1 -1
  72. package/dist/types.d.ts +52 -3
  73. package/dist/types.d.ts.map +1 -1
  74. package/package.json +1 -1
  75. package/src/components/DegenParticlesOverlay.tsx +5 -5
  76. package/src/components/LiveChart.tsx +37 -66
  77. package/src/components/LiveChartSeries.tsx +18 -6
  78. package/src/components/LoadingOverlay.tsx +53 -12
  79. package/src/components/YAxisOverlay.tsx +38 -2
  80. package/src/constants.ts +3 -3
  81. package/src/core/historyRangeCache.ts +109 -0
  82. package/src/core/liveChartEngineTick.ts +41 -63
  83. package/src/core/liveChartSeriesEngineTick.ts +18 -5
  84. package/src/core/resolveConfig.ts +1 -1
  85. package/src/core/useHistoryRevision.ts +36 -0
  86. package/src/core/useLiveChartEngine.ts +159 -64
  87. package/src/core/useLiveChartSeriesEngine.ts +22 -2
  88. package/src/draw/candleBodyPath.ts +38 -0
  89. package/src/draw/lineFillPaths.ts +63 -0
  90. package/src/draw/volume.ts +21 -23
  91. package/src/draw/volumeRange.ts +51 -0
  92. package/src/hooks/crosshairShared.ts +29 -0
  93. package/src/hooks/useCandlePaths.ts +68 -94
  94. package/src/hooks/useChartPaths.ts +87 -111
  95. package/src/hooks/useCrosshair.ts +15 -3
  96. package/src/hooks/useDegen.ts +10 -6
  97. package/src/hooks/useDemandFrameLoop.ts +82 -0
  98. package/src/hooks/useLoadingLook.ts +30 -0
  99. package/src/hooks/useMarkers.ts +18 -4
  100. package/src/hooks/useMultiSeriesDegen.ts +7 -3
  101. package/src/hooks/usePanScroll.ts +5 -0
  102. package/src/hooks/usePinchZoom.ts +5 -0
  103. package/src/hooks/useReferenceDrag.ts +28 -14
  104. package/src/hooks/useReferenceLineGrouping.ts +72 -0
  105. package/src/hooks/useVolumeRange.ts +40 -0
  106. package/src/hooks/useXAxis.ts +27 -3
  107. package/src/hooks/useYAxis.ts +18 -2
  108. package/src/index.ts +1 -0
  109. package/src/math/rangeAnimation.ts +28 -0
  110. package/src/math/referenceDrag.ts +21 -4
  111. package/src/math/referenceGroup.ts +2 -2
  112. package/src/math/spline.ts +16 -8
  113. package/src/math/squiggly.ts +12 -0
  114. package/src/types.ts +53 -3
@@ -0,0 +1,28 @@
1
+ import type { RangeAnimationConfig } from "../types";
2
+
3
+ // Worklet closures capture local functions when the caller is initialized.
4
+ function resolveSpeed(smoothing: number, speed: number | undefined): number {
5
+ "worklet";
6
+ return speed === undefined || !Number.isFinite(speed)
7
+ ? smoothing
8
+ : Math.max(0, Math.min(1, speed));
9
+ }
10
+
11
+ /** Select per-bound easing while preserving immediate expansion and reduced motion. */
12
+ export function rangeAnimationSpeed(
13
+ smoothing: number,
14
+ config: RangeAnimationConfig | undefined,
15
+ expanding: boolean,
16
+ disjoint = false,
17
+ ): number {
18
+ "worklet";
19
+ if (smoothing >= 1 || (expanding && !config?.animateExpansion)) return 1;
20
+ const speed = resolveSpeed(
21
+ smoothing,
22
+ expanding ? config?.expansionSmoothing : config?.contractionSmoothing,
23
+ );
24
+ // Until the ranges overlap, contraction must not outrun the expanding bound.
25
+ return !expanding && disjoint && config?.animateExpansion
26
+ ? Math.min(speed, resolveSpeed(smoothing, config.expansionSmoothing))
27
+ : speed;
28
+ }
@@ -17,16 +17,29 @@ export function clampToBounds(
17
17
  return Math.min(hi, Math.max(lo, value));
18
18
  }
19
19
 
20
+ /**
21
+ * Where a touch may grab each line: the touch `x` and, index-aligned with the
22
+ * chart's `referenceLines`, each line's `grabRange` (`[from, to]`, canvas px) —
23
+ * `null` / `undefined` for a line grabbed anywhere along it.
24
+ */
25
+ export interface GrabRangeProbe {
26
+ x: number;
27
+ ranges: readonly (readonly [number, number] | null | undefined)[];
28
+ }
29
+
20
30
  /**
21
31
  * Index of the draggable line whose handle-Y is nearest the touch `y`, within
22
32
  * `slop` px — or `-1` when none is in reach. `handleYs` is index-aligned with the
23
- * chart's `referenceLines`; entries `< 0` (not draggable / off-screen / not laid
24
- * out) are skipped. Ties favor the later (topmost-drawn) line.
33
+ * chart's `referenceLines`; entries `< 0` (not draggable / not laid out) are
34
+ * skipped; off-screen lines pin to the nearest plot edge. Ties favor the later
35
+ * (topmost-drawn) line. With `grab`, a line
36
+ * whose `grabRange` does not contain the touch `x` is skipped too.
25
37
  */
26
38
  export function nearestDraggableIndex(
27
39
  handleYs: number[],
28
40
  y: number,
29
41
  slop: number,
42
+ grab?: GrabRangeProbe,
30
43
  ): number {
31
44
  "worklet";
32
45
  let best = -1;
@@ -34,6 +47,8 @@ export function nearestDraggableIndex(
34
47
  for (let i = 0; i < handleYs.length; i++) {
35
48
  const hy = handleYs[i];
36
49
  if (hy < 0) continue;
50
+ const range = grab?.ranges[i];
51
+ if (range && (grab.x < range[0] || grab.x > range[1])) continue;
37
52
  const d = Math.abs(hy - y);
38
53
  if (d <= bestDist) {
39
54
  bestDist = d;
@@ -49,17 +64,19 @@ export function nearestDraggableIndex(
49
64
  * or already dragging) owns the touch outright, wherever the asking gesture says
50
65
  * the finger is: the scrub pan can activate mid-drag and asks with its
51
66
  * touch-DOWN point, which a longer drag has carried the line away from. With no
52
- * line grabbed, it is the geometric reach test around the handles.
67
+ * line grabbed, it is the geometric reach test around the handles (and, with
68
+ * `grab`, inside each line's `grabRange`).
53
69
  */
54
70
  export function referenceDragOwnsTouch(
55
71
  dragIndex: number,
56
72
  handleYs: number[],
57
73
  y: number,
58
74
  slop: number,
75
+ grab?: GrabRangeProbe,
59
76
  ): boolean {
60
77
  "worklet";
61
78
  if (dragIndex >= 0) return true;
62
- return nearestDraggableIndex(handleYs, y, slop) >= 0;
79
+ return nearestDraggableIndex(handleYs, y, slop, grab) >= 0;
63
80
  }
64
81
 
65
82
  /**
@@ -26,8 +26,8 @@ export interface ReferenceGrouping {
26
26
 
27
27
  /**
28
28
  * Single-linkage cluster of reference-line handle Ys: lines whose sorted Y gaps are
29
- * all `<= radius` chain into one group. Entries `< 0` (not a Form-A line / off the
30
- * canvas) are ignored. Returns which lines are collapsed (`hidden`) plus a centroid
29
+ * all `<= radius` chain into one group. Entries `< 0` (not a Form-A line / not laid
30
+ * out) are ignored. Returns which lines are collapsed (`hidden`) plus a centroid
31
31
  * + count per multi-line cluster. A non-positive `radius` disables grouping.
32
32
  */
33
33
  export function groupReferenceLines(
@@ -60,6 +60,9 @@ export function drawSpline(
60
60
  startPoint = 0,
61
61
  /** Last point index to draw (exclusive). Defaults to the full array. */
62
62
  endPoint = pts.length >> 1,
63
+ /** Optional paired sinks receive identical verbs from the same curve math. */
64
+ second?: SplinePathSink,
65
+ third?: SplinePathSink,
63
66
  ) {
64
67
  "worklet";
65
68
  const start = Math.max(0, startPoint);
@@ -70,12 +73,16 @@ export function drawSpline(
70
73
  for (let i = 1; i < n; i++) {
71
74
  const point = (start + i) * 2;
72
75
  path.lineTo(pts[point], pts[point + 1]);
76
+ second?.lineTo(pts[point], pts[point + 1]);
77
+ third?.lineTo(pts[point], pts[point + 1]);
73
78
  }
74
79
  return;
75
80
  }
76
81
  if (n === 2) {
77
82
  const point = (start + 1) * 2;
78
83
  path.lineTo(pts[point], pts[point + 1]);
84
+ second?.lineTo(pts[point], pts[point + 1]);
85
+ third?.lineTo(pts[point], pts[point + 1]);
79
86
  return;
80
87
  }
81
88
 
@@ -123,14 +130,15 @@ export function drawSpline(
123
130
  const i2 = (start + i) * 2;
124
131
  const j2 = i2 + 2;
125
132
  const hi = h[i];
126
- path.cubicTo(
127
- pts[i2] + hi / 3,
128
- pts[i2 + 1] + (m[i] * hi) / 3,
129
- pts[j2] - hi / 3,
130
- pts[j2 + 1] - (m[i + 1] * hi) / 3,
131
- pts[j2],
132
- pts[j2 + 1],
133
- );
133
+ const x1 = pts[i2] + hi / 3;
134
+ const y1 = pts[i2 + 1] + (m[i] * hi) / 3;
135
+ const x2 = pts[j2] - hi / 3;
136
+ const y2 = pts[j2 + 1] - (m[i + 1] * hi) / 3;
137
+ const x = pts[j2],
138
+ y = pts[j2 + 1];
139
+ path.cubicTo(x1, y1, x2, y2, x, y);
140
+ second?.cubicTo(x1, y1, x2, y2, x, y);
141
+ third?.cubicTo(x1, y1, x2, y2, x, y);
134
142
  }
135
143
  }
136
144
 
@@ -27,6 +27,18 @@ export function squigglyYAt(
27
27
  );
28
28
  }
29
29
 
30
+ /**
31
+ * The squiggle's clock, in seconds: wall time. The loading shell
32
+ * (`LoadingOverlay`) and the reveal's morph (`useChartPaths`) both phase their
33
+ * wave on it rather than on `engine.timestamp`, which a `nowOverride` freezes
34
+ * between data updates (freezing the loading line with it). Sharing one clock
35
+ * keeps the wave continuous where the shell hands over to the morph.
36
+ */
37
+ export function squiggleClockSeconds(): number {
38
+ "worklet";
39
+ return Date.now() / 1000;
40
+ }
41
+
30
42
  /**
31
43
  * Build a flat [x0,y0,x1,y1,...] point array for a standalone squiggly line
32
44
  * spanning the full chart area (used in loading / empty state).
package/src/types.ts CHANGED
@@ -191,6 +191,18 @@ export interface ReferenceLine {
191
191
  * it controlled. No effect on bands / time bands. Default `false`.
192
192
  */
193
193
  draggable?: boolean;
194
+ /**
195
+ * Where along a draggable line a press may grab it: a canvas x-range in px,
196
+ * `[from, to]`, ends included — typically the span of a custom tag drawn with
197
+ * `renderReferenceLine` (measure it with `onLayout`; a left-pinned tag starts 2 px
198
+ * inside the plot's left edge). Omit to grab the line anywhere along it (the
199
+ * default). With a range, a pan, scrub or page scroll that merely starts near the
200
+ * line no longer moves it; a press inside the range grabs it as before (same Y
201
+ * reach). `from > to` makes the line ungrabbable. A JS value: leave a little
202
+ * slack for a tag that changes width (off-axis, a live price). Applies only to
203
+ * draggable Form-A lines.
204
+ */
205
+ grabRange?: [number, number];
194
206
  /**
195
207
  * Snap the dragged value to this increment (e.g. `0.01` for cents, `0.5` for a
196
208
  * tick size) so drops land on round levels. Omit for free dragging. Applies only
@@ -334,7 +346,9 @@ export interface ReferenceLineRenderProps {
334
346
  * lines whose handles fall within {@link ReferenceLineGroupingConfig.radius} px of
335
347
  * each other collapse into a single count handle, so a cluster of nearby orders /
336
348
  * alerts reads as one tag instead of an unreadable pile. Pass `true` for defaults
337
- * or an object to tune the proximity radius.
349
+ * or an object to tune the proximity radius. Badged off-axis lines group at either
350
+ * plot edge; off-axis lines with no badge are hidden and do not count. Custom tags
351
+ * are excluded.
338
352
  */
339
353
  export interface ReferenceLineGroupingConfig {
340
354
  /**
@@ -757,8 +771,8 @@ export interface YAxisConfig {
757
771
  * numbers; they track the live range each frame.
758
772
  *
759
773
  * `minGap` still acts as a floor: if `count` labels won't fit at least
760
- * `minGap` px apart, the count is reduced to what fits. Clamped to at most 15
761
- * (the label pool size). Omit (or `0`) for the default dynamic grid.
774
+ * `minGap` px apart, the count is reduced to what fits. Clamped to at most 15.
775
+ * Omit (or `0`) for the default dynamic grid.
762
776
  */
763
777
  count?: number;
764
778
  /**
@@ -2258,6 +2272,25 @@ export interface LoadingConfig {
2258
2272
  axisLabels?: boolean;
2259
2273
  }
2260
2274
 
2275
+ /** Y-range easing shared by both charts, independent of value/window tracking. */
2276
+ export interface RangeAnimationConfig {
2277
+ /** Ease outward bounds instead of snapping. Default `false`. */
2278
+ animateExpansion?: boolean;
2279
+ /**
2280
+ * Fraction of the remaining gap closed per 60fps frame when a bound expands.
2281
+ * Inherits `smoothing`; only used with `animateExpansion: true`. Finite values
2282
+ * are clamped to 0..1; non-finite values inherit `smoothing`.
2283
+ */
2284
+ expansionSmoothing?: number;
2285
+ /**
2286
+ * Fraction of the remaining gap closed per 60fps frame when a bound contracts.
2287
+ * Inherits `smoothing`. Finite values are clamped to 0..1; non-finite values
2288
+ * inherit `smoothing`. While animated expansion moves toward a disjoint fit,
2289
+ * contraction is limited to the expansion speed so bounds cannot cross.
2290
+ */
2291
+ contractionSmoothing?: number;
2292
+ }
2293
+
2261
2294
  /** Props shared between `LiveChart` and `LiveChartSeries`. */
2262
2295
  export interface LiveChartCoreProps {
2263
2296
  /** Color scheme. Default `"dark"`. */
@@ -2324,6 +2357,14 @@ export interface LiveChartCoreProps {
2324
2357
  * `lerpSpeed`. Default `0.08`.
2325
2358
  */
2326
2359
  smoothing?: number;
2360
+ /**
2361
+ * Control Y-range expansion and contraction independently of `smoothing` for
2362
+ * value/window tracking. Omission preserves instant expansion and eased
2363
+ * contraction. Uses frame-rate-independent exponential easing, not a fixed
2364
+ * duration. `smoothing: 1`, explicit `snapKey` changes, static charts, and active
2365
+ * manual Y-scale dragging remain immediate. Axis-label fades use `metrics.grid`.
2366
+ */
2367
+ rangeAnimation?: RangeAnimationConfig;
2327
2368
  /**
2328
2369
  * Snap the framing to its target in a single frame whenever this key changes —
2329
2370
  * without giving up smooth live ticks. On a timeframe / dataset switch, the
@@ -2704,6 +2745,15 @@ export interface LiveChartProps extends LiveChartCoreProps {
2704
2745
  * @experimental
2705
2746
  */
2706
2747
  isFrameLoopActive?: SharedValue<boolean>;
2748
+ /**
2749
+ * Experimental single-series demand scheduling. Stop engine frames after a
2750
+ * paused, parked, or fixed-time chart settles; shared input changes and
2751
+ * gestures wake it on the UI thread. Default false. Live scrolling, pulse,
2752
+ * loading/reveal, and enabled degen/trade effects keep the engine awake.
2753
+ * Does not cache a bitmap or disable gestures. `static` takes precedence.
2754
+ * @experimental
2755
+ */
2756
+ autoSleep?: boolean;
2707
2757
  /**
2708
2758
  * Optional development counter for engine frames that did or did not change
2709
2759
  * tracked engine values. It is not a count of Skia redraws. Supplying it adds