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.
- package/dist/components/AxisLabelOverlay.d.ts +5 -1
- package/dist/components/AxisLabelOverlay.d.ts.map +1 -1
- package/dist/components/CrosshairOverlay.d.ts +4 -2
- package/dist/components/CrosshairOverlay.d.ts.map +1 -1
- package/dist/components/CustomMarkerOverlay.d.ts.map +1 -1
- package/dist/components/CustomThresholdBadgeOverlay.d.ts +18 -0
- package/dist/components/CustomThresholdBadgeOverlay.d.ts.map +1 -0
- package/dist/components/CustomTooltipOverlay.d.ts +4 -2
- package/dist/components/CustomTooltipOverlay.d.ts.map +1 -1
- package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
- package/dist/components/ExtremaConnectorOverlay.d.ts +5 -1
- package/dist/components/ExtremaConnectorOverlay.d.ts.map +1 -1
- package/dist/components/LiveChart.d.ts.map +1 -1
- package/dist/components/LiveChartSeries.d.ts.map +1 -1
- package/dist/components/MarkerOverlay.d.ts +4 -2
- package/dist/components/MarkerOverlay.d.ts.map +1 -1
- package/dist/components/ReferenceLineOverlay.d.ts +10 -5
- package/dist/components/ReferenceLineOverlay.d.ts.map +1 -1
- package/dist/components/ReferenceLineSeriesOverlay.d.ts +19 -0
- package/dist/components/ReferenceLineSeriesOverlay.d.ts.map +1 -0
- package/dist/core/chartDataPresence.d.ts +8 -0
- package/dist/core/chartDataPresence.d.ts.map +1 -0
- package/dist/core/liveChartEngineTick.d.ts +6 -1
- package/dist/core/liveChartEngineTick.d.ts.map +1 -1
- package/dist/core/resolveConfig.d.ts +32 -1
- package/dist/core/resolveConfig.d.ts.map +1 -1
- package/dist/core/useLiveChartEngine.d.ts +9 -1
- package/dist/core/useLiveChartEngine.d.ts.map +1 -1
- package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
- package/dist/draw/candle.d.ts +3 -1
- package/dist/draw/candle.d.ts.map +1 -1
- package/dist/draw/candleGap.d.ts +14 -0
- package/dist/draw/candleGap.d.ts.map +1 -0
- package/dist/draw/lineGap.d.ts +25 -0
- package/dist/draw/lineGap.d.ts.map +1 -0
- package/dist/draw/markerAtlas.d.ts +3 -2
- package/dist/draw/markerAtlas.d.ts.map +1 -1
- package/dist/hooks/crosshairShared.d.ts +7 -3
- package/dist/hooks/crosshairShared.d.ts.map +1 -1
- package/dist/hooks/useCandleGapPaths.d.ts +12 -0
- package/dist/hooks/useCandleGapPaths.d.ts.map +1 -0
- package/dist/hooks/useChartPaths.d.ts +4 -1
- package/dist/hooks/useChartPaths.d.ts.map +1 -1
- package/dist/hooks/useChartReveal.d.ts +1 -1
- package/dist/hooks/useChartReveal.d.ts.map +1 -1
- package/dist/hooks/useCrosshair.d.ts +9 -5
- package/dist/hooks/useCrosshair.d.ts.map +1 -1
- package/dist/hooks/useDegen.d.ts.map +1 -1
- package/dist/hooks/useLineGapPaths.d.ts +10 -0
- package/dist/hooks/useLineGapPaths.d.ts.map +1 -0
- package/dist/hooks/useLiveChartHasData.d.ts +2 -2
- package/dist/hooks/useLiveChartHasData.d.ts.map +1 -1
- package/dist/hooks/useReferenceLine.d.ts +4 -3
- package/dist/hooks/useReferenceLine.d.ts.map +1 -1
- package/dist/hooks/useReferenceLineSeries.d.ts +23 -0
- package/dist/hooks/useReferenceLineSeries.d.ts.map +1 -0
- package/dist/hooks/useReverseMorphEngineInputs.d.ts.map +1 -1
- package/dist/hooks/useThreshold.d.ts +13 -13
- package/dist/hooks/useThreshold.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/math/candleGaps.d.ts +18 -0
- package/dist/math/candleGaps.d.ts.map +1 -0
- package/dist/math/referenceLineSeries.d.ts +12 -0
- package/dist/math/referenceLineSeries.d.ts.map +1 -0
- package/dist/math/referenceLines.d.ts +5 -5
- package/dist/math/referenceLines.d.ts.map +1 -1
- package/dist/math/spline.d.ts +5 -1
- package/dist/math/spline.d.ts.map +1 -1
- package/dist/types.d.ts +191 -17
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AxisLabelOverlay.tsx +162 -81
- package/src/components/CrosshairOverlay.tsx +394 -147
- package/src/components/CustomMarkerOverlay.tsx +9 -6
- package/src/components/CustomThresholdBadgeOverlay.tsx +74 -0
- package/src/components/CustomTooltipOverlay.tsx +7 -3
- package/src/components/DegenParticlesOverlay.tsx +34 -23
- package/src/components/ExtremaConnectorOverlay.tsx +43 -3
- package/src/components/LiveChart.tsx +1918 -974
- package/src/components/LiveChartSeries.tsx +445 -296
- package/src/components/MarkerOverlay.tsx +215 -156
- package/src/components/ReferenceLineOverlay.tsx +113 -55
- package/src/components/ReferenceLineSeriesOverlay.tsx +141 -0
- package/src/core/chartDataPresence.ts +24 -0
- package/src/core/liveChartEngineTick.ts +34 -1
- package/src/core/resolveConfig.ts +186 -0
- package/src/core/useLiveChartEngine.ts +36 -1
- package/src/core/useLiveChartSeriesEngine.ts +2 -0
- package/src/draw/candle.ts +1 -1
- package/src/draw/candleGap.ts +132 -0
- package/src/draw/lineGap.ts +180 -0
- package/src/draw/markerAtlas.ts +8 -3
- package/src/hooks/crosshairShared.ts +92 -11
- package/src/hooks/useCandleGapPaths.ts +88 -0
- package/src/hooks/useChartPaths.ts +81 -22
- package/src/hooks/useChartReveal.ts +1 -1
- package/src/hooks/useCrosshair.ts +178 -69
- package/src/hooks/useDegen.ts +82 -53
- package/src/hooks/useLineGapPaths.ts +76 -0
- package/src/hooks/useLiveChartHasData.ts +8 -4
- package/src/hooks/useReferenceLine.ts +6 -5
- package/src/hooks/useReferenceLineSeries.ts +101 -0
- package/src/hooks/useReverseMorphEngineInputs.ts +11 -20
- package/src/hooks/useThreshold.ts +31 -22
- package/src/index.ts +15 -0
- package/src/math/candleGaps.ts +120 -0
- package/src/math/referenceLineSeries.ts +83 -0
- package/src/math/referenceLines.ts +34 -6
- package/src/math/spline.ts +15 -5
- 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
|
-
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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
|
}
|