react-native-livechart 4.10.0 → 4.12.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/README.md +24 -0
  2. package/dist/components/CrosshairLine.d.ts +5 -1
  3. package/dist/components/CrosshairLine.d.ts.map +1 -1
  4. package/dist/components/CrosshairOverlay.d.ts +3 -1
  5. package/dist/components/CrosshairOverlay.d.ts.map +1 -1
  6. package/dist/components/CustomReferenceLineOverlay.d.ts +19 -12
  7. package/dist/components/CustomReferenceLineOverlay.d.ts.map +1 -1
  8. package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
  9. package/dist/components/DotOverlay.d.ts +3 -5
  10. package/dist/components/DotOverlay.d.ts.map +1 -1
  11. package/dist/components/LeftEdgeFade.d.ts +3 -1
  12. package/dist/components/LeftEdgeFade.d.ts.map +1 -1
  13. package/dist/components/LiveChart.d.ts.map +1 -1
  14. package/dist/components/LiveChartSeries.d.ts.map +1 -1
  15. package/dist/components/LoadingOverlay.d.ts +3 -1
  16. package/dist/components/LoadingOverlay.d.ts.map +1 -1
  17. package/dist/components/MarkerOverlay.d.ts.map +1 -1
  18. package/dist/components/MultiSeriesDots.d.ts +3 -1
  19. package/dist/components/MultiSeriesDots.d.ts.map +1 -1
  20. package/dist/components/MultiSeriesTooltipStack.d.ts.map +1 -1
  21. package/dist/components/MultiSeriesValueLabels.d.ts +3 -1
  22. package/dist/components/MultiSeriesValueLabels.d.ts.map +1 -1
  23. package/dist/components/MultiSeriesValueLines.d.ts +3 -1
  24. package/dist/components/MultiSeriesValueLines.d.ts.map +1 -1
  25. package/dist/components/PerSeriesTooltipOverlay.d.ts +19 -0
  26. package/dist/components/PerSeriesTooltipOverlay.d.ts.map +1 -0
  27. package/dist/components/ReferenceLineOverlay.d.ts +20 -6
  28. package/dist/components/ReferenceLineOverlay.d.ts.map +1 -1
  29. package/dist/components/ThresholdSplitShader.d.ts.map +1 -1
  30. package/dist/components/YAxisOverlay.d.ts +3 -1
  31. package/dist/components/YAxisOverlay.d.ts.map +1 -1
  32. package/dist/components/thresholdSplitShaderSource.d.ts +13 -0
  33. package/dist/components/thresholdSplitShaderSource.d.ts.map +1 -0
  34. package/dist/core/liveIndicatorVisibility.d.ts +9 -0
  35. package/dist/core/liveIndicatorVisibility.d.ts.map +1 -0
  36. package/dist/core/resolveConfig.d.ts +29 -0
  37. package/dist/core/resolveConfig.d.ts.map +1 -1
  38. package/dist/core/useLiveChartEngine.d.ts +9 -1
  39. package/dist/core/useLiveChartEngine.d.ts.map +1 -1
  40. package/dist/core/useLiveChartSeriesEngine.d.ts +10 -5
  41. package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
  42. package/dist/draw/particleAtlas.d.ts +3 -2
  43. package/dist/draw/particleAtlas.d.ts.map +1 -1
  44. package/dist/hooks/crosshairSeries.d.ts +10 -2
  45. package/dist/hooks/crosshairSeries.d.ts.map +1 -1
  46. package/dist/hooks/crosshairShared.d.ts +37 -2
  47. package/dist/hooks/crosshairShared.d.ts.map +1 -1
  48. package/dist/hooks/delayedPanGuard.d.ts +66 -8
  49. package/dist/hooks/delayedPanGuard.d.ts.map +1 -1
  50. package/dist/hooks/useChartPaths.d.ts +5 -9
  51. package/dist/hooks/useChartPaths.d.ts.map +1 -1
  52. package/dist/hooks/useCrosshair.d.ts +7 -1
  53. package/dist/hooks/useCrosshair.d.ts.map +1 -1
  54. package/dist/hooks/useCrosshairSeries.d.ts +22 -3
  55. package/dist/hooks/useCrosshairSeries.d.ts.map +1 -1
  56. package/dist/hooks/useMomentum.d.ts +1 -1
  57. package/dist/hooks/useMomentum.d.ts.map +1 -1
  58. package/dist/hooks/useMultiSeriesLinePaths.d.ts +4 -4
  59. package/dist/hooks/useMultiSeriesLinePaths.d.ts.map +1 -1
  60. package/dist/hooks/usePanScroll.d.ts +15 -1
  61. package/dist/hooks/usePanScroll.d.ts.map +1 -1
  62. package/dist/index.d.ts +1 -1
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/math/lerp.d.ts.map +1 -1
  65. package/dist/math/momentum.d.ts +1 -1
  66. package/dist/math/momentum.d.ts.map +1 -1
  67. package/dist/math/referenceLines.d.ts +7 -0
  68. package/dist/math/referenceLines.d.ts.map +1 -1
  69. package/dist/math/squiggly.d.ts +6 -3
  70. package/dist/math/squiggly.d.ts.map +1 -1
  71. package/dist/math/threshold.d.ts +2 -2
  72. package/dist/types.d.ts +184 -16
  73. package/dist/types.d.ts.map +1 -1
  74. package/package.json +1 -1
  75. package/src/components/CrosshairLine.tsx +21 -1
  76. package/src/components/CrosshairOverlay.tsx +48 -35
  77. package/src/components/CustomReferenceLineOverlay.tsx +58 -20
  78. package/src/components/DegenParticlesOverlay.tsx +40 -5
  79. package/src/components/DotOverlay.tsx +24 -8
  80. package/src/components/LeftEdgeFade.tsx +12 -6
  81. package/src/components/LiveChart.tsx +186 -53
  82. package/src/components/LiveChartSeries.tsx +214 -29
  83. package/src/components/LoadingOverlay.tsx +26 -12
  84. package/src/components/MarkerOverlay.tsx +20 -3
  85. package/src/components/MultiSeriesDots.tsx +4 -2
  86. package/src/components/MultiSeriesTooltipStack.tsx +4 -2
  87. package/src/components/MultiSeriesValueLabels.tsx +4 -2
  88. package/src/components/MultiSeriesValueLines.tsx +4 -2
  89. package/src/components/PerSeriesTooltipOverlay.tsx +287 -0
  90. package/src/components/ReferenceLineOverlay.tsx +274 -141
  91. package/src/components/ThresholdSplitShader.tsx +5 -37
  92. package/src/components/YAxisOverlay.tsx +5 -1
  93. package/src/components/thresholdSplitShaderSource.ts +70 -0
  94. package/src/core/liveIndicatorVisibility.ts +25 -0
  95. package/src/core/resolveConfig.ts +86 -0
  96. package/src/core/useLiveChartEngine.ts +110 -42
  97. package/src/core/useLiveChartSeriesEngine.ts +137 -70
  98. package/src/draw/particleAtlas.ts +21 -10
  99. package/src/hooks/crosshairSeries.ts +262 -33
  100. package/src/hooks/crosshairShared.ts +41 -2
  101. package/src/hooks/delayedPanGuard.ts +111 -6
  102. package/src/hooks/useChartPaths.ts +36 -15
  103. package/src/hooks/useCrosshair.ts +73 -14
  104. package/src/hooks/useCrosshairSeries.ts +106 -13
  105. package/src/hooks/useMomentum.ts +8 -1
  106. package/src/hooks/useMultiSeriesLinePaths.ts +15 -9
  107. package/src/hooks/usePanScroll.ts +46 -5
  108. package/src/index.ts +2 -0
  109. package/src/math/lerp.ts +7 -0
  110. package/src/math/momentum.ts +22 -5
  111. package/src/math/referenceLines.ts +38 -0
  112. package/src/math/squiggly.ts +28 -11
  113. package/src/math/threshold.ts +2 -2
  114. package/src/types.ts +197 -17
@@ -1,7 +1,6 @@
1
1
  import { Circle, Group } from "@shopify/react-native-skia";
2
2
 
3
3
  import { useDerivedValue, type SharedValue } from "react-native-reanimated";
4
- import { MAX_MULTI_SERIES } from "../constants";
5
4
  import type { ChartPadding } from "../draw/line";
6
5
  import type {
7
6
  ResolvedDotRingConfig,
@@ -118,6 +117,7 @@ export function MultiSeriesDots({
118
117
  color,
119
118
  pulse,
120
119
  viewEnd,
120
+ seriesCount,
121
121
  }: {
122
122
  engine: MultiEngineState;
123
123
  padding: ChartPadding;
@@ -132,10 +132,12 @@ export function MultiSeriesDots({
132
132
  pulse: ResolvedPulseConfig | null;
133
133
  /** Pan/zoom right-edge override — pulse is frozen-out while scrolled back. */
134
134
  viewEnd?: SharedValue<number | null>;
135
+ /** Number of live series slots to mount. */
136
+ seriesCount: number;
135
137
  }) {
136
138
  return (
137
139
  <Group>
138
- {Array.from({ length: MAX_MULTI_SERIES }, (_, i) => (
140
+ {Array.from({ length: seriesCount }, (_, i) => (
139
141
  <SeriesDotAtIndex
140
142
  key={i}
141
143
  index={i}
@@ -4,11 +4,13 @@ import {
4
4
  type SkFont,
5
5
  } from "@shopify/react-native-skia";
6
6
  import { useDerivedValue, type SharedValue } from "react-native-reanimated";
7
- import { MAX_MULTI_SERIES } from "../constants";
8
7
  import type { TooltipLayout } from "../hooks/crosshairShared";
9
8
  import type { LiveChartPalette } from "../types";
10
9
 
11
- const TOOLTIP_STACK_SLOTS = MAX_MULTI_SERIES + 1;
10
+ // Candle tooltips have exactly O/H/L/C + time. This component is only mounted
11
+ // for candle mode, so reserving the multi-series capacity registered 40 unused
12
+ // derived-value mappers (8 empty rows × 5 mappers).
13
+ const TOOLTIP_STACK_SLOTS = 5;
12
14
 
13
15
  function TooltipStackLine({
14
16
  index,
@@ -5,7 +5,6 @@ import {
5
5
  } from "@shopify/react-native-skia";
6
6
  import { useDerivedValue } from "react-native-reanimated";
7
7
 
8
- import { MAX_MULTI_SERIES } from "../constants";
9
8
  import type { ChartPadding } from "../draw/line";
10
9
  import type { MultiEngineState } from "../core/useLiveChartEngine";
11
10
 
@@ -78,16 +77,19 @@ export function MultiSeriesValueLabels({
78
77
  colors,
79
78
  font,
80
79
  dotRadius,
80
+ seriesCount,
81
81
  }: {
82
82
  engine: MultiEngineState;
83
83
  padding: ChartPadding;
84
84
  colors: string[];
85
85
  font: SkFont;
86
86
  dotRadius: number;
87
+ /** Number of live series slots to mount. */
88
+ seriesCount: number;
87
89
  }) {
88
90
  return (
89
91
  <Group>
90
- {Array.from({ length: MAX_MULTI_SERIES }, (_, i) => (
92
+ {Array.from({ length: seriesCount }, (_, i) => (
91
93
  <SeriesValueLabelAtIndex
92
94
  key={i}
93
95
  index={i}
@@ -1,7 +1,6 @@
1
1
  import { DashPathEffect, Group, Path } from "@shopify/react-native-skia";
2
2
 
3
3
  import { useDerivedValue } from "react-native-reanimated";
4
- import { MAX_MULTI_SERIES } from "../constants";
5
4
  import type { ChartPadding } from "../draw/line";
6
5
  import type { ResolvedValueLineConfig } from "../core/resolveConfig";
7
6
  import type { MultiEngineState } from "../core/useLiveChartEngine";
@@ -72,15 +71,18 @@ export function MultiSeriesValueLines({
72
71
  padding,
73
72
  colors,
74
73
  config,
74
+ seriesCount,
75
75
  }: {
76
76
  engine: MultiEngineState;
77
77
  padding: ChartPadding;
78
78
  colors: string[];
79
79
  config: ResolvedValueLineConfig;
80
+ /** Number of live series slots to mount. */
81
+ seriesCount: number;
80
82
  }) {
81
83
  return (
82
84
  <Group>
83
- {Array.from({ length: MAX_MULTI_SERIES }, (_, i) => (
85
+ {Array.from({ length: seriesCount }, (_, i) => (
84
86
  <SeriesValueLineAtIndex
85
87
  key={i}
86
88
  index={i}
@@ -0,0 +1,287 @@
1
+ import {
2
+ Circle,
3
+ Group,
4
+ RoundedRect,
5
+ Text as SkiaText,
6
+ type SkFont,
7
+ } from "@shopify/react-native-skia";
8
+ import {
9
+ useDerivedValue,
10
+ type DerivedValue,
11
+ type SharedValue,
12
+ } from "react-native-reanimated";
13
+ import type { ResolvedPerSeriesTooltipConfig } from "../core/resolveConfig";
14
+ import type { TooltipLayout } from "../hooks/crosshairShared";
15
+ import type { LiveChartPalette } from "../types";
16
+
17
+ type TooltipLayoutValue =
18
+ | SharedValue<TooltipLayout>
19
+ | DerivedValue<TooltipLayout>;
20
+
21
+ function TimePill({
22
+ layout,
23
+ font,
24
+ palette,
25
+ config,
26
+ background,
27
+ color,
28
+ borderColor,
29
+ }: {
30
+ layout: TooltipLayoutValue;
31
+ font: SkFont;
32
+ palette: LiveChartPalette;
33
+ config: ResolvedPerSeriesTooltipConfig;
34
+ background?: string;
35
+ color?: string;
36
+ borderColor?: string;
37
+ }) {
38
+ const opacity = useDerivedValue(() =>
39
+ layout.value.perSeries?.timePill ? 1 : 0,
40
+ );
41
+ const x = useDerivedValue(
42
+ () => layout.value.perSeries?.timePill?.x ?? -400,
43
+ );
44
+ const y = useDerivedValue(
45
+ () => layout.value.perSeries?.timePill?.y ?? 0,
46
+ );
47
+ const w = useDerivedValue(
48
+ () => layout.value.perSeries?.timePill?.w ?? 0,
49
+ );
50
+ const h = useDerivedValue(
51
+ () => layout.value.perSeries?.timePill?.h ?? 0,
52
+ );
53
+ const text = useDerivedValue(
54
+ () => layout.value.perSeries?.timePill?.text ?? "",
55
+ );
56
+ const textX = useDerivedValue(
57
+ () => layout.value.perSeries?.timePill?.textX ?? -400,
58
+ );
59
+ const baselineY = useDerivedValue(
60
+ () => layout.value.perSeries?.timePill?.baselineY ?? 0,
61
+ );
62
+ const clip = useDerivedValue(() => ({
63
+ x: layout.value.perSeries?.timePill?.x ?? -400,
64
+ y: layout.value.perSeries?.timePill?.y ?? 0,
65
+ width: layout.value.perSeries?.timePill?.w ?? 0,
66
+ height: layout.value.perSeries?.timePill?.h ?? 0,
67
+ }));
68
+
69
+ return (
70
+ <Group opacity={opacity}>
71
+ <RoundedRect
72
+ x={x}
73
+ y={y}
74
+ width={w}
75
+ height={h}
76
+ r={config.timePillRadius}
77
+ color={background ?? palette.tooltipBg}
78
+ />
79
+ <RoundedRect
80
+ x={x}
81
+ y={y}
82
+ width={w}
83
+ height={h}
84
+ r={config.timePillRadius}
85
+ color={borderColor ?? palette.tooltipBorder}
86
+ style="stroke"
87
+ strokeWidth={1}
88
+ />
89
+ <Group clip={clip}>
90
+ <SkiaText
91
+ x={textX}
92
+ y={baselineY}
93
+ text={text}
94
+ font={font}
95
+ color={color ?? palette.tooltipText}
96
+ />
97
+ </Group>
98
+ </Group>
99
+ );
100
+ }
101
+
102
+ function SeriesPill({
103
+ index,
104
+ layout,
105
+ font,
106
+ palette,
107
+ config,
108
+ background,
109
+ labelColor,
110
+ valueColor,
111
+ borderColor,
112
+ }: {
113
+ index: number;
114
+ layout: TooltipLayoutValue;
115
+ font: SkFont;
116
+ palette: LiveChartPalette;
117
+ config: ResolvedPerSeriesTooltipConfig;
118
+ background?: string;
119
+ labelColor?: string;
120
+ valueColor?: string;
121
+ borderColor?: string;
122
+ }) {
123
+ const opacity = useDerivedValue(() => {
124
+ const pills = layout.value.perSeries?.pills;
125
+ return pills && index < pills.length ? 1 : 0;
126
+ });
127
+ const x = useDerivedValue(
128
+ () => layout.value.perSeries?.pills[index]?.x ?? -400,
129
+ );
130
+ const y = useDerivedValue(
131
+ () => layout.value.perSeries?.pills[index]?.y ?? 0,
132
+ );
133
+ const w = useDerivedValue(
134
+ () => layout.value.perSeries?.pills[index]?.w ?? 0,
135
+ );
136
+ const h = useDerivedValue(
137
+ () => layout.value.perSeries?.pills[index]?.h ?? 0,
138
+ );
139
+ const anchorX = useDerivedValue(
140
+ () => layout.value.perSeries?.pills[index]?.anchorX ?? -400,
141
+ );
142
+ const anchorY = useDerivedValue(
143
+ () => layout.value.perSeries?.pills[index]?.anchorY ?? -400,
144
+ );
145
+ const dotX = useDerivedValue(
146
+ () => layout.value.perSeries?.pills[index]?.dotX ?? -400,
147
+ );
148
+ const dotY = useDerivedValue(
149
+ () => layout.value.perSeries?.pills[index]?.dotY ?? -400,
150
+ );
151
+ const dotColor = useDerivedValue(
152
+ () => layout.value.perSeries?.pills[index]?.color ?? palette.tooltipText,
153
+ );
154
+ const label = useDerivedValue(
155
+ () => layout.value.perSeries?.pills[index]?.label ?? "",
156
+ );
157
+ const labelX = useDerivedValue(
158
+ () => layout.value.perSeries?.pills[index]?.labelX ?? -400,
159
+ );
160
+ const value = useDerivedValue(
161
+ () => layout.value.perSeries?.pills[index]?.value ?? "",
162
+ );
163
+ const valueX = useDerivedValue(
164
+ () => layout.value.perSeries?.pills[index]?.valueX ?? -400,
165
+ );
166
+ const baselineY = useDerivedValue(
167
+ () => layout.value.perSeries?.pills[index]?.baselineY ?? 0,
168
+ );
169
+ const clip = useDerivedValue(() => ({
170
+ x: layout.value.perSeries?.pills[index]?.x ?? -400,
171
+ y: layout.value.perSeries?.pills[index]?.y ?? 0,
172
+ width: layout.value.perSeries?.pills[index]?.w ?? 0,
173
+ height: layout.value.perSeries?.pills[index]?.h ?? 0,
174
+ }));
175
+
176
+ return (
177
+ <Group opacity={opacity}>
178
+ <Circle
179
+ cx={anchorX}
180
+ cy={anchorY}
181
+ r={config.intersectionDotSize / 2}
182
+ color={dotColor}
183
+ />
184
+ <RoundedRect
185
+ x={x}
186
+ y={y}
187
+ width={w}
188
+ height={h}
189
+ r={config.seriesPillRadius}
190
+ color={background ?? palette.tooltipBg}
191
+ />
192
+ <RoundedRect
193
+ x={x}
194
+ y={y}
195
+ width={w}
196
+ height={h}
197
+ r={config.seriesPillRadius}
198
+ color={borderColor ?? palette.tooltipBorder}
199
+ style="stroke"
200
+ strokeWidth={1}
201
+ />
202
+ <Group clip={clip}>
203
+ <Circle
204
+ cx={dotX}
205
+ cy={dotY}
206
+ r={config.seriesPillDotSize / 2}
207
+ color={dotColor}
208
+ />
209
+ <SkiaText
210
+ x={labelX}
211
+ y={baselineY}
212
+ text={label}
213
+ font={font}
214
+ color={labelColor ?? palette.tooltipText}
215
+ />
216
+ <SkiaText
217
+ x={valueX}
218
+ y={baselineY}
219
+ text={value}
220
+ font={font}
221
+ color={valueColor ?? labelColor ?? palette.tooltipText}
222
+ />
223
+ </Group>
224
+ </Group>
225
+ );
226
+ }
227
+
228
+ /** Skia-only per-series tooltip renderer; every position is SharedValue-driven. */
229
+ export function PerSeriesTooltipOverlay({
230
+ layout,
231
+ font,
232
+ palette,
233
+ config,
234
+ seriesCount,
235
+ tooltipBackground,
236
+ tooltipColor,
237
+ tooltipBorderColor,
238
+ }: {
239
+ layout: TooltipLayoutValue;
240
+ font: SkFont;
241
+ palette: LiveChartPalette;
242
+ config: ResolvedPerSeriesTooltipConfig;
243
+ seriesCount: number;
244
+ tooltipBackground?: string;
245
+ tooltipColor?: string;
246
+ tooltipBorderColor?: string;
247
+ }) {
248
+ const timeBackground =
249
+ config.timePillBackground ?? tooltipBackground;
250
+ const timeColor = config.timePillColor ?? tooltipColor;
251
+ const timeBorder =
252
+ config.timePillBorderColor ?? tooltipBorderColor;
253
+ const seriesBackground =
254
+ config.seriesPillBackground ?? tooltipBackground;
255
+ const seriesLabelColor =
256
+ config.seriesPillLabelColor ?? tooltipColor;
257
+ const seriesBorder =
258
+ config.seriesPillBorderColor ?? tooltipBorderColor;
259
+
260
+ return (
261
+ <Group>
262
+ <TimePill
263
+ layout={layout}
264
+ font={font}
265
+ palette={palette}
266
+ config={config}
267
+ background={timeBackground}
268
+ color={timeColor}
269
+ borderColor={timeBorder}
270
+ />
271
+ {Array.from({ length: seriesCount }, (_, index) => (
272
+ <SeriesPill
273
+ key={index}
274
+ index={index}
275
+ layout={layout}
276
+ font={font}
277
+ palette={palette}
278
+ config={config}
279
+ background={seriesBackground}
280
+ labelColor={seriesLabelColor}
281
+ valueColor={config.seriesPillValueColor}
282
+ borderColor={seriesBorder}
283
+ />
284
+ ))}
285
+ </Group>
286
+ );
287
+ }