react-native-livechart 4.20.0 → 4.21.1

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 (111) hide show
  1. package/dist/components/AxisLabelOverlay.d.ts +5 -1
  2. package/dist/components/AxisLabelOverlay.d.ts.map +1 -1
  3. package/dist/components/CrosshairOverlay.d.ts +4 -2
  4. package/dist/components/CrosshairOverlay.d.ts.map +1 -1
  5. package/dist/components/CustomMarkerOverlay.d.ts.map +1 -1
  6. package/dist/components/CustomThresholdBadgeOverlay.d.ts +18 -0
  7. package/dist/components/CustomThresholdBadgeOverlay.d.ts.map +1 -0
  8. package/dist/components/CustomTooltipOverlay.d.ts +4 -2
  9. package/dist/components/CustomTooltipOverlay.d.ts.map +1 -1
  10. package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
  11. package/dist/components/ExtremaConnectorOverlay.d.ts +5 -1
  12. package/dist/components/ExtremaConnectorOverlay.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/MarkerOverlay.d.ts +4 -2
  16. package/dist/components/MarkerOverlay.d.ts.map +1 -1
  17. package/dist/components/ReferenceLineOverlay.d.ts +10 -5
  18. package/dist/components/ReferenceLineOverlay.d.ts.map +1 -1
  19. package/dist/components/ReferenceLineSeriesOverlay.d.ts +19 -0
  20. package/dist/components/ReferenceLineSeriesOverlay.d.ts.map +1 -0
  21. package/dist/core/chartDataPresence.d.ts +8 -0
  22. package/dist/core/chartDataPresence.d.ts.map +1 -0
  23. package/dist/core/liveChartEngineTick.d.ts +6 -1
  24. package/dist/core/liveChartEngineTick.d.ts.map +1 -1
  25. package/dist/core/resolveConfig.d.ts +32 -1
  26. package/dist/core/resolveConfig.d.ts.map +1 -1
  27. package/dist/core/useLiveChartEngine.d.ts +9 -1
  28. package/dist/core/useLiveChartEngine.d.ts.map +1 -1
  29. package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
  30. package/dist/draw/candle.d.ts +3 -1
  31. package/dist/draw/candle.d.ts.map +1 -1
  32. package/dist/draw/candleGap.d.ts +14 -0
  33. package/dist/draw/candleGap.d.ts.map +1 -0
  34. package/dist/draw/lineGap.d.ts +25 -0
  35. package/dist/draw/lineGap.d.ts.map +1 -0
  36. package/dist/draw/markerAtlas.d.ts +3 -2
  37. package/dist/draw/markerAtlas.d.ts.map +1 -1
  38. package/dist/hooks/crosshairShared.d.ts +7 -3
  39. package/dist/hooks/crosshairShared.d.ts.map +1 -1
  40. package/dist/hooks/useCandleGapPaths.d.ts +12 -0
  41. package/dist/hooks/useCandleGapPaths.d.ts.map +1 -0
  42. package/dist/hooks/useChartPaths.d.ts +4 -1
  43. package/dist/hooks/useChartPaths.d.ts.map +1 -1
  44. package/dist/hooks/useChartReveal.d.ts +1 -1
  45. package/dist/hooks/useChartReveal.d.ts.map +1 -1
  46. package/dist/hooks/useCrosshair.d.ts +9 -5
  47. package/dist/hooks/useCrosshair.d.ts.map +1 -1
  48. package/dist/hooks/useDegen.d.ts.map +1 -1
  49. package/dist/hooks/useLineGapPaths.d.ts +10 -0
  50. package/dist/hooks/useLineGapPaths.d.ts.map +1 -0
  51. package/dist/hooks/useLiveChartHasData.d.ts +2 -2
  52. package/dist/hooks/useLiveChartHasData.d.ts.map +1 -1
  53. package/dist/hooks/useReferenceLine.d.ts +4 -3
  54. package/dist/hooks/useReferenceLine.d.ts.map +1 -1
  55. package/dist/hooks/useReferenceLineSeries.d.ts +23 -0
  56. package/dist/hooks/useReferenceLineSeries.d.ts.map +1 -0
  57. package/dist/hooks/useReverseMorphEngineInputs.d.ts.map +1 -1
  58. package/dist/hooks/useThreshold.d.ts +13 -13
  59. package/dist/hooks/useThreshold.d.ts.map +1 -1
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/math/candleGaps.d.ts +18 -0
  63. package/dist/math/candleGaps.d.ts.map +1 -0
  64. package/dist/math/referenceLineSeries.d.ts +12 -0
  65. package/dist/math/referenceLineSeries.d.ts.map +1 -0
  66. package/dist/math/referenceLines.d.ts +5 -5
  67. package/dist/math/referenceLines.d.ts.map +1 -1
  68. package/dist/math/spline.d.ts +5 -1
  69. package/dist/math/spline.d.ts.map +1 -1
  70. package/dist/types.d.ts +191 -17
  71. package/dist/types.d.ts.map +1 -1
  72. package/package.json +1 -1
  73. package/src/components/AxisLabelOverlay.tsx +162 -81
  74. package/src/components/CrosshairOverlay.tsx +394 -147
  75. package/src/components/CustomMarkerOverlay.tsx +9 -6
  76. package/src/components/CustomThresholdBadgeOverlay.tsx +74 -0
  77. package/src/components/CustomTooltipOverlay.tsx +7 -3
  78. package/src/components/DegenParticlesOverlay.tsx +34 -23
  79. package/src/components/ExtremaConnectorOverlay.tsx +43 -3
  80. package/src/components/LiveChart.tsx +1918 -974
  81. package/src/components/LiveChartSeries.tsx +445 -296
  82. package/src/components/MarkerOverlay.tsx +215 -156
  83. package/src/components/ReferenceLineOverlay.tsx +113 -55
  84. package/src/components/ReferenceLineSeriesOverlay.tsx +141 -0
  85. package/src/core/chartDataPresence.ts +24 -0
  86. package/src/core/liveChartEngineTick.ts +34 -1
  87. package/src/core/resolveConfig.ts +186 -0
  88. package/src/core/useLiveChartEngine.ts +36 -1
  89. package/src/core/useLiveChartSeriesEngine.ts +2 -0
  90. package/src/draw/candle.ts +1 -1
  91. package/src/draw/candleGap.ts +132 -0
  92. package/src/draw/lineGap.ts +180 -0
  93. package/src/draw/markerAtlas.ts +8 -3
  94. package/src/hooks/crosshairShared.ts +92 -11
  95. package/src/hooks/useCandleGapPaths.ts +88 -0
  96. package/src/hooks/useChartPaths.ts +81 -22
  97. package/src/hooks/useChartReveal.ts +1 -1
  98. package/src/hooks/useCrosshair.ts +178 -69
  99. package/src/hooks/useDegen.ts +82 -53
  100. package/src/hooks/useLineGapPaths.ts +76 -0
  101. package/src/hooks/useLiveChartHasData.ts +8 -4
  102. package/src/hooks/useReferenceLine.ts +6 -5
  103. package/src/hooks/useReferenceLineSeries.ts +101 -0
  104. package/src/hooks/useReverseMorphEngineInputs.ts +11 -20
  105. package/src/hooks/useThreshold.ts +31 -22
  106. package/src/index.ts +15 -0
  107. package/src/math/candleGaps.ts +120 -0
  108. package/src/math/referenceLineSeries.ts +83 -0
  109. package/src/math/referenceLines.ts +34 -6
  110. package/src/math/spline.ts +15 -5
  111. package/src/types.ts +202 -17
@@ -56,6 +56,22 @@ export const EXTREMA_EDGE_INSET = 2;
56
56
  * reads it to estimate where the edge label ends. */
57
57
  export const EXTREMA_LABEL_FONT_SIZE = 11;
58
58
 
59
+ /** Whether the high and low extrema resolve to the exact same data point. */
60
+ export function extremaPointsCoincide(
61
+ firstTime: number,
62
+ firstValue: number,
63
+ secondTime: number,
64
+ secondValue: number,
65
+ ): boolean {
66
+ "worklet";
67
+ return (
68
+ Number.isFinite(firstTime) &&
69
+ Number.isFinite(firstValue) &&
70
+ firstTime === secondTime &&
71
+ firstValue === secondValue
72
+ );
73
+ }
74
+
59
75
  /**
60
76
  * The batteries-included axis edge label — an animated RN text driven by a
61
77
  * `SharedValue<number>` (the chart's current top / bottom Y-axis bound). The
@@ -131,6 +147,7 @@ function ExtremaAxisLabel({
131
147
  dotSize,
132
148
  dot,
133
149
  render,
150
+ suppressWhen,
134
151
  }: {
135
152
  /** `"top"` floats above the max point; `"bottom"` below the min point. */
136
153
  side: "top" | "bottom";
@@ -160,6 +177,11 @@ function ExtremaAxisLabel({
160
177
  /** Whether to draw the marker dot. */
161
178
  dot: boolean;
162
179
  render?: () => React.ReactElement | null;
180
+ /** Hide this side when it resolves to the same point as the other extremum. */
181
+ suppressWhen?: {
182
+ timeSV: SharedValue<number>;
183
+ valueSV: SharedValue<number>;
184
+ };
163
185
  }) {
164
186
  const isCustom = render != null;
165
187
  // Resolved dot geometry. `hasDot` also gates the label's vertical offset (it
@@ -181,7 +203,16 @@ function ExtremaAxisLabel({
181
203
  useAnimatedReaction(
182
204
  () => {
183
205
  const v = valueSV.get();
184
- return isCustom || !Number.isFinite(v) ? "" : format(v);
206
+ const t = timeSV.get();
207
+ const suppressed =
208
+ suppressWhen != null &&
209
+ extremaPointsCoincide(
210
+ t,
211
+ v,
212
+ suppressWhen.timeSV.get(),
213
+ suppressWhen.valueSV.get(),
214
+ );
215
+ return isCustom || !Number.isFinite(v) || suppressed ? "" : format(v);
185
216
  },
186
217
  (curr, prev) => {
187
218
  if (curr !== prev) scheduleOnRN(setValueText, curr);
@@ -211,6 +242,13 @@ function ExtremaAxisLabel({
211
242
 
212
243
  if (
213
244
  !Number.isFinite(value) ||
245
+ (suppressWhen != null &&
246
+ extremaPointsCoincide(
247
+ time,
248
+ value,
249
+ suppressWhen.timeSV.get(),
250
+ suppressWhen.valueSV.get(),
251
+ )) ||
214
252
  cw === 0 ||
215
253
  ch === 0 ||
216
254
  chartW <= 0 ||
@@ -324,6 +362,90 @@ function ExtremaAxisLabel({
324
362
  );
325
363
  }
326
364
 
365
+ /** One configured top/bottom label, rendered either on its edge or extremum. */
366
+ function AxisLabelSide({
367
+ side,
368
+ label,
369
+ extrema,
370
+ timeSV,
371
+ valueSV,
372
+ edgeValue,
373
+ engine,
374
+ formatValue,
375
+ defaultColor,
376
+ padding,
377
+ extremaTimeOffset,
378
+ hideExtrema,
379
+ suppressWhen,
380
+ }: {
381
+ side: "top" | "bottom";
382
+ label: ResolvedAxisLabelConfig | null;
383
+ extrema: boolean;
384
+ timeSV?: SharedValue<number>;
385
+ valueSV?: SharedValue<number>;
386
+ edgeValue: SharedValue<number>;
387
+ engine: ChartEngineLayout;
388
+ formatValue: (v: number) => string;
389
+ defaultColor: string;
390
+ padding: ChartPadding;
391
+ extremaTimeOffset: number;
392
+ hideExtrema: boolean;
393
+ suppressWhen?: {
394
+ timeSV: SharedValue<number>;
395
+ valueSV: SharedValue<number>;
396
+ };
397
+ }) {
398
+ if (!label) return null;
399
+
400
+ if (extrema) {
401
+ if (hideExtrema || !timeSV || !valueSV) return null;
402
+ return (
403
+ <ExtremaAxisLabel
404
+ side={side}
405
+ timeSV={timeSV}
406
+ valueSV={valueSV}
407
+ timeOffset={extremaTimeOffset}
408
+ edgeAnchor={label.position === "extrema-edge"}
409
+ engine={engine}
410
+ padding={padding}
411
+ format={label.format ?? formatValue}
412
+ color={label.color ?? defaultColor}
413
+ font={labelFont(label)}
414
+ dotColor={label.dotColor}
415
+ dotSize={label.dotSize}
416
+ dot={label.dot}
417
+ render={label.render ?? undefined}
418
+ suppressWhen={suppressWhen}
419
+ />
420
+ );
421
+ }
422
+
423
+ return (
424
+ <View
425
+ style={{
426
+ position: "absolute",
427
+ ...(side === "top"
428
+ ? { top: padding.top }
429
+ : { bottom: padding.bottom }),
430
+ left: padding.left,
431
+ right: padding.right,
432
+ }}
433
+ >
434
+ {label.render ? (
435
+ label.render()
436
+ ) : (
437
+ <BuiltInAxisValueLabel
438
+ value={edgeValue}
439
+ format={label.format ?? formatValue}
440
+ color={label.color ?? defaultColor}
441
+ position={label.position}
442
+ font={labelFont(label)}
443
+ />
444
+ )}
445
+ </View>
446
+ );
447
+ }
448
+
327
449
  /**
328
450
  * React Native overlay (NOT Skia) floating axis edge labels over the Skia
329
451
  * canvas — `topLabel` pinned to the plot's top edge and `bottomLabel` to its
@@ -353,6 +475,7 @@ export function AxisLabelOverlay({
353
475
  defaultColor,
354
476
  padding,
355
477
  extremaTimeOffset = 0,
478
+ hideExtrema = false,
356
479
  }: {
357
480
  topLabel: ResolvedAxisLabelConfig | null;
358
481
  bottomLabel: ResolvedAxisLabelConfig | null;
@@ -366,6 +489,8 @@ export function AxisLabelOverlay({
366
489
  * candle's drawn center; `0` (default) for line / multi-series.
367
490
  */
368
491
  extremaTimeOffset?: number;
492
+ /** Hide point-anchored extrema while the chart is showing its loading shell. */
493
+ hideExtrema?: boolean;
369
494
  }) {
370
495
  if (!topLabel && !bottomLabel) return null;
371
496
 
@@ -384,86 +509,42 @@ export function AxisLabelOverlay({
384
509
 
385
510
  return (
386
511
  <View style={StyleSheet.absoluteFill} pointerEvents="none">
387
- {topLabel &&
388
- (topExtrema ? (
389
- <ExtremaAxisLabel
390
- side="top"
391
- timeSV={engine.extremaMaxTime!}
392
- valueSV={engine.extremaMaxValue!}
393
- timeOffset={extremaTimeOffset}
394
- edgeAnchor={topMode === "extrema-edge"}
395
- engine={engine}
396
- padding={padding}
397
- format={topLabel.format ?? formatValue}
398
- color={topLabel.color ?? defaultColor}
399
- font={labelFont(topLabel)}
400
- dotColor={topLabel.dotColor}
401
- dotSize={topLabel.dotSize}
402
- dot={topLabel.dot}
403
- render={topLabel.render ?? undefined}
404
- />
405
- ) : (
406
- <View
407
- style={{
408
- position: "absolute",
409
- top: padding.top,
410
- left: padding.left,
411
- right: padding.right,
412
- }}
413
- >
414
- {topLabel.render ? (
415
- topLabel.render()
416
- ) : (
417
- <BuiltInAxisValueLabel
418
- value={engine.displayMax}
419
- format={topLabel.format ?? formatValue}
420
- color={topLabel.color ?? defaultColor}
421
- position={topLabel.position}
422
- font={labelFont(topLabel)}
423
- />
424
- )}
425
- </View>
426
- ))}
427
- {bottomLabel &&
428
- (bottomExtrema ? (
429
- <ExtremaAxisLabel
430
- side="bottom"
431
- timeSV={engine.extremaMinTime!}
432
- valueSV={engine.extremaMinValue!}
433
- timeOffset={extremaTimeOffset}
434
- edgeAnchor={bottomMode === "extrema-edge"}
435
- engine={engine}
436
- padding={padding}
437
- format={bottomLabel.format ?? formatValue}
438
- color={bottomLabel.color ?? defaultColor}
439
- font={labelFont(bottomLabel)}
440
- dotColor={bottomLabel.dotColor}
441
- dotSize={bottomLabel.dotSize}
442
- dot={bottomLabel.dot}
443
- render={bottomLabel.render ?? undefined}
444
- />
445
- ) : (
446
- <View
447
- style={{
448
- position: "absolute",
449
- bottom: padding.bottom,
450
- left: padding.left,
451
- right: padding.right,
452
- }}
453
- >
454
- {bottomLabel.render ? (
455
- bottomLabel.render()
456
- ) : (
457
- <BuiltInAxisValueLabel
458
- value={engine.displayMin}
459
- format={bottomLabel.format ?? formatValue}
460
- color={bottomLabel.color ?? defaultColor}
461
- position={bottomLabel.position}
462
- font={labelFont(bottomLabel)}
463
- />
464
- )}
465
- </View>
466
- ))}
512
+ <AxisLabelSide
513
+ side="top"
514
+ label={topLabel}
515
+ extrema={topExtrema}
516
+ timeSV={engine.extremaMaxTime}
517
+ valueSV={engine.extremaMaxValue}
518
+ edgeValue={engine.displayMax}
519
+ engine={engine}
520
+ formatValue={formatValue}
521
+ defaultColor={defaultColor}
522
+ padding={padding}
523
+ extremaTimeOffset={extremaTimeOffset}
524
+ hideExtrema={hideExtrema}
525
+ />
526
+ <AxisLabelSide
527
+ side="bottom"
528
+ label={bottomLabel}
529
+ extrema={bottomExtrema}
530
+ timeSV={engine.extremaMinTime}
531
+ valueSV={engine.extremaMinValue}
532
+ edgeValue={engine.displayMin}
533
+ engine={engine}
534
+ formatValue={formatValue}
535
+ defaultColor={defaultColor}
536
+ padding={padding}
537
+ extremaTimeOffset={extremaTimeOffset}
538
+ hideExtrema={hideExtrema}
539
+ suppressWhen={
540
+ topExtrema
541
+ ? {
542
+ timeSV: engine.extremaMaxTime!,
543
+ valueSV: engine.extremaMaxValue!,
544
+ }
545
+ : undefined
546
+ }
547
+ />
467
548
  </View>
468
549
  );
469
550
  }