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.
- package/README.md +24 -0
- package/dist/components/CrosshairLine.d.ts +5 -1
- package/dist/components/CrosshairLine.d.ts.map +1 -1
- package/dist/components/CrosshairOverlay.d.ts +3 -1
- package/dist/components/CrosshairOverlay.d.ts.map +1 -1
- package/dist/components/CustomReferenceLineOverlay.d.ts +19 -12
- package/dist/components/CustomReferenceLineOverlay.d.ts.map +1 -1
- package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
- package/dist/components/DotOverlay.d.ts +3 -5
- package/dist/components/DotOverlay.d.ts.map +1 -1
- package/dist/components/LeftEdgeFade.d.ts +3 -1
- package/dist/components/LeftEdgeFade.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/LoadingOverlay.d.ts +3 -1
- package/dist/components/LoadingOverlay.d.ts.map +1 -1
- package/dist/components/MarkerOverlay.d.ts.map +1 -1
- package/dist/components/MultiSeriesDots.d.ts +3 -1
- package/dist/components/MultiSeriesDots.d.ts.map +1 -1
- package/dist/components/MultiSeriesTooltipStack.d.ts.map +1 -1
- package/dist/components/MultiSeriesValueLabels.d.ts +3 -1
- package/dist/components/MultiSeriesValueLabels.d.ts.map +1 -1
- package/dist/components/MultiSeriesValueLines.d.ts +3 -1
- package/dist/components/MultiSeriesValueLines.d.ts.map +1 -1
- package/dist/components/PerSeriesTooltipOverlay.d.ts +19 -0
- package/dist/components/PerSeriesTooltipOverlay.d.ts.map +1 -0
- package/dist/components/ReferenceLineOverlay.d.ts +20 -6
- package/dist/components/ReferenceLineOverlay.d.ts.map +1 -1
- package/dist/components/ThresholdSplitShader.d.ts.map +1 -1
- package/dist/components/YAxisOverlay.d.ts +3 -1
- package/dist/components/YAxisOverlay.d.ts.map +1 -1
- package/dist/components/thresholdSplitShaderSource.d.ts +13 -0
- package/dist/components/thresholdSplitShaderSource.d.ts.map +1 -0
- package/dist/core/liveIndicatorVisibility.d.ts +9 -0
- package/dist/core/liveIndicatorVisibility.d.ts.map +1 -0
- package/dist/core/resolveConfig.d.ts +29 -0
- 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 +10 -5
- package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
- package/dist/draw/particleAtlas.d.ts +3 -2
- package/dist/draw/particleAtlas.d.ts.map +1 -1
- package/dist/hooks/crosshairSeries.d.ts +10 -2
- package/dist/hooks/crosshairSeries.d.ts.map +1 -1
- package/dist/hooks/crosshairShared.d.ts +37 -2
- package/dist/hooks/crosshairShared.d.ts.map +1 -1
- package/dist/hooks/delayedPanGuard.d.ts +66 -8
- package/dist/hooks/delayedPanGuard.d.ts.map +1 -1
- package/dist/hooks/useChartPaths.d.ts +5 -9
- package/dist/hooks/useChartPaths.d.ts.map +1 -1
- package/dist/hooks/useCrosshair.d.ts +7 -1
- package/dist/hooks/useCrosshair.d.ts.map +1 -1
- package/dist/hooks/useCrosshairSeries.d.ts +22 -3
- package/dist/hooks/useCrosshairSeries.d.ts.map +1 -1
- package/dist/hooks/useMomentum.d.ts +1 -1
- package/dist/hooks/useMomentum.d.ts.map +1 -1
- package/dist/hooks/useMultiSeriesLinePaths.d.ts +4 -4
- package/dist/hooks/useMultiSeriesLinePaths.d.ts.map +1 -1
- package/dist/hooks/usePanScroll.d.ts +15 -1
- package/dist/hooks/usePanScroll.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/math/lerp.d.ts.map +1 -1
- package/dist/math/momentum.d.ts +1 -1
- package/dist/math/momentum.d.ts.map +1 -1
- package/dist/math/referenceLines.d.ts +7 -0
- package/dist/math/referenceLines.d.ts.map +1 -1
- package/dist/math/squiggly.d.ts +6 -3
- package/dist/math/squiggly.d.ts.map +1 -1
- package/dist/math/threshold.d.ts +2 -2
- package/dist/types.d.ts +184 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/CrosshairLine.tsx +21 -1
- package/src/components/CrosshairOverlay.tsx +48 -35
- package/src/components/CustomReferenceLineOverlay.tsx +58 -20
- package/src/components/DegenParticlesOverlay.tsx +40 -5
- package/src/components/DotOverlay.tsx +24 -8
- package/src/components/LeftEdgeFade.tsx +12 -6
- package/src/components/LiveChart.tsx +186 -53
- package/src/components/LiveChartSeries.tsx +214 -29
- package/src/components/LoadingOverlay.tsx +26 -12
- package/src/components/MarkerOverlay.tsx +20 -3
- package/src/components/MultiSeriesDots.tsx +4 -2
- package/src/components/MultiSeriesTooltipStack.tsx +4 -2
- package/src/components/MultiSeriesValueLabels.tsx +4 -2
- package/src/components/MultiSeriesValueLines.tsx +4 -2
- package/src/components/PerSeriesTooltipOverlay.tsx +287 -0
- package/src/components/ReferenceLineOverlay.tsx +274 -141
- package/src/components/ThresholdSplitShader.tsx +5 -37
- package/src/components/YAxisOverlay.tsx +5 -1
- package/src/components/thresholdSplitShaderSource.ts +70 -0
- package/src/core/liveIndicatorVisibility.ts +25 -0
- package/src/core/resolveConfig.ts +86 -0
- package/src/core/useLiveChartEngine.ts +110 -42
- package/src/core/useLiveChartSeriesEngine.ts +137 -70
- package/src/draw/particleAtlas.ts +21 -10
- package/src/hooks/crosshairSeries.ts +262 -33
- package/src/hooks/crosshairShared.ts +41 -2
- package/src/hooks/delayedPanGuard.ts +111 -6
- package/src/hooks/useChartPaths.ts +36 -15
- package/src/hooks/useCrosshair.ts +73 -14
- package/src/hooks/useCrosshairSeries.ts +106 -13
- package/src/hooks/useMomentum.ts +8 -1
- package/src/hooks/useMultiSeriesLinePaths.ts +15 -9
- package/src/hooks/usePanScroll.ts +46 -5
- package/src/index.ts +2 -0
- package/src/math/lerp.ts +7 -0
- package/src/math/momentum.ts +22 -5
- package/src/math/referenceLines.ts +38 -0
- package/src/math/squiggly.ts +28 -11
- package/src/math/threshold.ts +2 -2
- package/src/types.ts +197 -17
package/src/math/lerp.ts
CHANGED
|
@@ -12,6 +12,13 @@ export function lerp(
|
|
|
12
12
|
dt = MS_PER_FRAME_60FPS,
|
|
13
13
|
): number {
|
|
14
14
|
"worklet";
|
|
15
|
+
// speed >= 1 means "snap in one frame". Computing it through the exponential
|
|
16
|
+
// would evaluate 0 ** (dt / frame), which is Infinity for a negative frame
|
|
17
|
+
// delta. When current === target, the resulting 0 * -Infinity becomes NaN
|
|
18
|
+
// and is permanent once written back into a SharedValue. No broader guard:
|
|
19
|
+
// NaN inputs must keep propagating (the engine tick relies on a NaN
|
|
20
|
+
// displayValue staying NaN so the y-range block stays skipped).
|
|
21
|
+
if (speed >= 1) return target;
|
|
15
22
|
const factor = 1 - Math.pow(1 - speed, dt / MS_PER_FRAME_60FPS);
|
|
16
23
|
return current + (target - current) * factor;
|
|
17
24
|
}
|
package/src/math/momentum.ts
CHANGED
|
@@ -9,15 +9,32 @@ export function detectMomentum(
|
|
|
9
9
|
points: LiveChartPoint[],
|
|
10
10
|
lookback = 20,
|
|
11
11
|
threshold = 0.12,
|
|
12
|
+
endTime?: number,
|
|
12
13
|
): Momentum {
|
|
13
14
|
"worklet";
|
|
14
|
-
|
|
15
|
+
// `badge.followViewEdge` needs momentum at the historical window edge rather
|
|
16
|
+
// than at the live dataset tail. Points are chronological, so find the first
|
|
17
|
+
// sample after the inclusive cutoff without allocating a sliced array on the
|
|
18
|
+
// UI thread. With no cutoff, preserve the normal live-tail behavior.
|
|
19
|
+
let end = points.length;
|
|
20
|
+
if (endTime !== undefined) {
|
|
21
|
+
let lo = 0;
|
|
22
|
+
let hi = points.length;
|
|
23
|
+
while (lo < hi) {
|
|
24
|
+
const mid = (lo + hi) >> 1;
|
|
25
|
+
if (points[mid].time <= endTime) lo = mid + 1;
|
|
26
|
+
else hi = mid;
|
|
27
|
+
}
|
|
28
|
+
end = lo;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (end < 5) return "flat";
|
|
15
32
|
|
|
16
|
-
const start = Math.max(0,
|
|
33
|
+
const start = Math.max(0, end - lookback);
|
|
17
34
|
|
|
18
35
|
let min = Infinity;
|
|
19
36
|
let max = -Infinity;
|
|
20
|
-
for (let i = start; i <
|
|
37
|
+
for (let i = start; i < end; i++) {
|
|
21
38
|
const v = points[i].value;
|
|
22
39
|
if (v < min) min = v;
|
|
23
40
|
if (v > max) max = v;
|
|
@@ -25,9 +42,9 @@ export function detectMomentum(
|
|
|
25
42
|
const range = max - min;
|
|
26
43
|
if (range === 0) return "flat";
|
|
27
44
|
|
|
28
|
-
const tailStart = Math.max(start,
|
|
45
|
+
const tailStart = Math.max(start, end - 5);
|
|
29
46
|
const first = points[tailStart].value;
|
|
30
|
-
const last = points[
|
|
47
|
+
const last = points[end - 1].value;
|
|
31
48
|
const delta = last - first;
|
|
32
49
|
|
|
33
50
|
const absThreshold = range * threshold;
|
|
@@ -44,6 +44,44 @@ export function collectReferenceValues(lines: ReferenceLine[]): number[] {
|
|
|
44
44
|
return out;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Stable React keys for an ordered reference-line list. A caller-supplied `id`
|
|
49
|
+
* keeps the key stable across reordering; the visual config is a deterministic
|
|
50
|
+
* fallback for legacy lines. Equal fallback signatures receive a suffix so they
|
|
51
|
+
* remain distinct siblings.
|
|
52
|
+
*/
|
|
53
|
+
export function referenceLineReactKeys(
|
|
54
|
+
lines: readonly ReferenceLine[],
|
|
55
|
+
): string[] {
|
|
56
|
+
const occurrences = new Map<string, number>();
|
|
57
|
+
const keys: string[] = [];
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
const base = line.id ?? stableReferenceLineSignature(line);
|
|
60
|
+
const occurrence = occurrences.get(base) ?? 0;
|
|
61
|
+
occurrences.set(base, occurrence + 1);
|
|
62
|
+
keys.push(`${base}:${occurrence}`);
|
|
63
|
+
}
|
|
64
|
+
return keys;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Serializes render-relevant config without callback identity churn. */
|
|
68
|
+
function stableReferenceLineSignature(value: unknown): string {
|
|
69
|
+
if (Array.isArray(value)) {
|
|
70
|
+
return `[${value.map(stableReferenceLineSignature).join(",")}]`;
|
|
71
|
+
}
|
|
72
|
+
if (value !== null && typeof value === "object") {
|
|
73
|
+
const record = value as Record<string, unknown>;
|
|
74
|
+
const entries: string[] = [];
|
|
75
|
+
for (const key of Object.keys(record).sort()) {
|
|
76
|
+
const entry = record[key];
|
|
77
|
+
if (typeof entry === "function" || entry === undefined) continue;
|
|
78
|
+
entries.push(`${key}:${stableReferenceLineSignature(entry)}`);
|
|
79
|
+
}
|
|
80
|
+
return `{${entries.join(",")}}`;
|
|
81
|
+
}
|
|
82
|
+
return JSON.stringify(value) ?? "undefined";
|
|
83
|
+
}
|
|
84
|
+
|
|
47
85
|
/**
|
|
48
86
|
* Fully-resolved badge **style/shape** + anchor — the resolved counterpart of
|
|
49
87
|
* {@link BadgeStyleConfig} (`position` / `icon` / `showText` plus the style knobs).
|
package/src/math/squiggly.ts
CHANGED
|
@@ -31,6 +31,7 @@ export function squigglyYAt(
|
|
|
31
31
|
* Build a flat [x0,y0,x1,y1,...] point array for a standalone squiggly line
|
|
32
32
|
* spanning the full chart area (used in loading / empty state).
|
|
33
33
|
* Points are spaced ~4px apart for smooth curves.
|
|
34
|
+
* Pass `out` to reuse a caller-owned frame scratch.
|
|
34
35
|
*/
|
|
35
36
|
export function buildSquigglyPts(
|
|
36
37
|
canvasWidth: number,
|
|
@@ -39,17 +40,22 @@ export function buildSquigglyPts(
|
|
|
39
40
|
t: number,
|
|
40
41
|
base = 14,
|
|
41
42
|
speed = 1,
|
|
43
|
+
out?: number[],
|
|
42
44
|
): number[] {
|
|
43
45
|
"worklet";
|
|
46
|
+
const pts = out ?? [];
|
|
44
47
|
const leftEdge = padding.left;
|
|
45
48
|
const rightEdge = canvasWidth - padding.right;
|
|
46
49
|
const chartW = rightEdge - leftEdge;
|
|
47
|
-
if (chartW <= 0 || canvasHeight <= 0)
|
|
50
|
+
if (chartW <= 0 || canvasHeight <= 0) {
|
|
51
|
+
pts.length = 0;
|
|
52
|
+
return pts;
|
|
53
|
+
}
|
|
48
54
|
|
|
49
55
|
const centerY = (canvasHeight - padding.bottom + padding.top) / 2;
|
|
50
56
|
const step = 4;
|
|
51
57
|
const count = Math.ceil(chartW / step) + 1;
|
|
52
|
-
|
|
58
|
+
pts.length = count * 2;
|
|
53
59
|
for (let i = 0; i < count; i++) {
|
|
54
60
|
const x = leftEdge + Math.min(i * step, chartW);
|
|
55
61
|
pts[i * 2] = x;
|
|
@@ -61,6 +67,7 @@ export function buildSquigglyPts(
|
|
|
61
67
|
/**
|
|
62
68
|
* Given a real flat-pts array (from buildLinePoints), replace each Y with the
|
|
63
69
|
* squiggly Y at the same X. Used during the morph reveal.
|
|
70
|
+
* Pass `out` to reuse a caller-owned frame scratch.
|
|
64
71
|
*/
|
|
65
72
|
export function squigglifyPts(
|
|
66
73
|
flatPts: number[],
|
|
@@ -68,15 +75,17 @@ export function squigglifyPts(
|
|
|
68
75
|
centerY: number,
|
|
69
76
|
base = 14,
|
|
70
77
|
speed = 1,
|
|
78
|
+
out?: number[],
|
|
71
79
|
): number[] {
|
|
72
80
|
"worklet";
|
|
73
81
|
const n = flatPts.length;
|
|
74
|
-
const out
|
|
82
|
+
const target = out ?? [];
|
|
83
|
+
target.length = n;
|
|
75
84
|
for (let i = 0; i < n; i += 2) {
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
target[i] = flatPts[i];
|
|
86
|
+
target[i + 1] = squigglyYAt(flatPts[i], centerY, t, base, speed);
|
|
78
87
|
}
|
|
79
|
-
return
|
|
88
|
+
return target;
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
/**
|
|
@@ -97,6 +106,7 @@ export function smoothstep(t: number): number {
|
|
|
97
106
|
* distFromCentre = |x - chartCentreX| / (chartW / 2) // 0=centre, 1=edge
|
|
98
107
|
* weight = smoothstep((morphT - distFromCentre * 0.5) / 0.5)
|
|
99
108
|
* blendedY = fromY + (toY - fromY) * weight
|
|
109
|
+
* Pass `out` to reuse a caller-owned frame scratch.
|
|
100
110
|
*/
|
|
101
111
|
export function blendPtsY(
|
|
102
112
|
from: number[],
|
|
@@ -104,19 +114,26 @@ export function blendPtsY(
|
|
|
104
114
|
morphT: number,
|
|
105
115
|
padding: ChartPadding,
|
|
106
116
|
canvasWidth: number,
|
|
117
|
+
out?: number[],
|
|
107
118
|
): number[] {
|
|
108
119
|
"worklet";
|
|
109
120
|
const n = from.length;
|
|
110
|
-
if (n === 0) return to;
|
|
121
|
+
if (n === 0 && !out) return to;
|
|
111
122
|
const chartCentreX = (padding.left + canvasWidth - padding.right) / 2;
|
|
112
123
|
const halfChartW = (canvasWidth - padding.left - padding.right) / 2;
|
|
113
|
-
const out
|
|
124
|
+
const target = out ?? [];
|
|
125
|
+
const outputLength = n === 0 ? to.length : n;
|
|
126
|
+
target.length = outputLength;
|
|
127
|
+
if (n === 0) {
|
|
128
|
+
for (let i = 0; i < to.length; i++) target[i] = to[i];
|
|
129
|
+
return target;
|
|
130
|
+
}
|
|
114
131
|
for (let i = 0; i < n; i += 2) {
|
|
115
|
-
|
|
132
|
+
target[i] = to[i]; // X always from real pts
|
|
116
133
|
const distFromCentre =
|
|
117
134
|
halfChartW > 0 ? Math.abs(from[i] - chartCentreX) / halfChartW : 0;
|
|
118
135
|
const weight = smoothstep((morphT - distFromCentre * 0.5) / 0.5);
|
|
119
|
-
|
|
136
|
+
target[i + 1] = from[i + 1] + (to[i + 1] - from[i + 1]) * weight;
|
|
120
137
|
}
|
|
121
|
-
return
|
|
138
|
+
return target;
|
|
122
139
|
}
|
package/src/math/threshold.ts
CHANGED
|
@@ -12,8 +12,8 @@ import type { LiveChartPoint } from "../types";
|
|
|
12
12
|
* projected to this many evenly-spaced pixel-Y values across the plot, which the
|
|
13
13
|
* shader linearly interpolates between. ~one sample per 6px on a phone plot —
|
|
14
14
|
* fine enough that the line's crossing point is coloured accurately. The shader
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* selects between them through a balanced constant-index branch tree, so 64
|
|
16
|
+
* samples require at most six comparisons per covered fragment.
|
|
17
17
|
*/
|
|
18
18
|
export const THRESHOLD_SAMPLE_COUNT = 64;
|
|
19
19
|
|
package/src/types.ts
CHANGED
|
@@ -44,6 +44,10 @@ export type FontWeight =
|
|
|
44
44
|
/** Color scheme for the chart background, grid, and derived palette colors. */
|
|
45
45
|
export type ThemeMode = "light" | "dark";
|
|
46
46
|
|
|
47
|
+
/** Skia canvas composition mode. Android uses TextureView for `"transparent"`
|
|
48
|
+
* and an opaque SurfaceView for `"opaque"`. */
|
|
49
|
+
export type CanvasMode = "transparent" | "opaque";
|
|
50
|
+
|
|
47
51
|
/**
|
|
48
52
|
* Badge pill style.
|
|
49
53
|
* - `"default"` — accent-colored background with white text.
|
|
@@ -59,6 +63,11 @@ export type BadgeVariant = "default" | "minimal";
|
|
|
59
63
|
* - **Form C** — vertical time band between `from` and `to` (unix seconds).
|
|
60
64
|
*/
|
|
61
65
|
export interface ReferenceLine {
|
|
66
|
+
/**
|
|
67
|
+
* Stable identifier for this line. Supply a unique value when `referenceLines`
|
|
68
|
+
* may be reordered so the chart preserves the line's rendered identity.
|
|
69
|
+
*/
|
|
70
|
+
id?: string;
|
|
62
71
|
/** Form A — the Y-axis value where the horizontal line is drawn. */
|
|
63
72
|
value?: number;
|
|
64
73
|
/** Form B — horizontal band lower Y bound (paired with `valueTo`). */
|
|
@@ -249,14 +258,17 @@ export interface ReferenceLineBadgeConfig extends BadgeStyleConfig {
|
|
|
249
258
|
}
|
|
250
259
|
|
|
251
260
|
/**
|
|
252
|
-
* Context passed to a custom {@link LiveChartProps.renderReferenceLine}
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
261
|
+
* Context passed to a custom {@link LiveChartProps.renderReferenceLine} or
|
|
262
|
+
* {@link LiveChartProps.renderOffAxisReferenceLine} (and their
|
|
263
|
+
* `LiveChartSeries` counterparts). The chart floats the element you return over
|
|
264
|
+
* the canvas and pins it to the line's value on the UI thread (vertically centered
|
|
265
|
+
* on the line, horizontally at the badge / label position) — so it tracks the
|
|
266
|
+
* rescaling axis and any drag smoothly without JS re-renders, just like
|
|
267
|
+
* {@link TooltipRenderProps}. `renderReferenceLine` replaces the built-in pill /
|
|
268
|
+
* gutter label in every state; `renderOffAxisReferenceLine` replaces it only while
|
|
269
|
+
* the value is pinned above or below the visible plot. Bind the SharedValues to
|
|
270
|
+
* animated text (e.g. an animated `TextInput`) for the value to update on the UI
|
|
271
|
+
* thread too.
|
|
260
272
|
*/
|
|
261
273
|
export interface ReferenceLineRenderProps {
|
|
262
274
|
/** The reference line being rendered. */
|
|
@@ -587,7 +599,9 @@ export interface BadgeConfig extends BadgeStyleConfig {
|
|
|
587
599
|
* When the chart is scrolled back (see `timeScroll`), move the live-price
|
|
588
600
|
* indicators — the badge, the value line, and the live dot — to the price at
|
|
589
601
|
* the visible window's right edge instead of the live price, so they track the
|
|
590
|
-
* last visible price as you pan.
|
|
602
|
+
* last visible price as you pan. The badge's momentum color is derived at that
|
|
603
|
+
* same historical edge, so incoming live ticks do not recolor it. Default
|
|
604
|
+
* `false`.
|
|
591
605
|
*
|
|
592
606
|
* @experimental
|
|
593
607
|
*/
|
|
@@ -711,10 +725,102 @@ export interface XAxisConfig {
|
|
|
711
725
|
minGap?: number;
|
|
712
726
|
}
|
|
713
727
|
|
|
728
|
+
/**
|
|
729
|
+
* Morfi-style on-canvas tooltip for {@link LiveChartSeries}: a time-range pill
|
|
730
|
+
* above the guide plus one value pill at every visible series intersection.
|
|
731
|
+
*
|
|
732
|
+
* Enable it with `scrub={{ seriesTooltip: true }}` or pass this object to style
|
|
733
|
+
* and format the readout. It is ignored by the single-series {@link LiveChart}.
|
|
734
|
+
*/
|
|
735
|
+
export interface PerSeriesTooltipConfig {
|
|
736
|
+
/**
|
|
737
|
+
* Keep the value pills pinned to the visible series endpoints while idle.
|
|
738
|
+
* The guide and time pill remain hidden until a scrub starts. Default `false`.
|
|
739
|
+
*/
|
|
740
|
+
alwaysShow?: boolean;
|
|
741
|
+
/**
|
|
742
|
+
* Bucket width used by the time-range pill, in seconds. Omit to infer it from
|
|
743
|
+
* the latest positive interval in the first visible series.
|
|
744
|
+
*/
|
|
745
|
+
bucketSeconds?: number;
|
|
746
|
+
/**
|
|
747
|
+
* Format a value pill. The second argument identifies the series so one chart
|
|
748
|
+
* can dispatch to different unit formatters. Defaults to the chart's
|
|
749
|
+
* `formatValue`.
|
|
750
|
+
*
|
|
751
|
+
* Runs on the UI thread and must be worklet-safe.
|
|
752
|
+
*/
|
|
753
|
+
formatSeriesValue?: (value: number, seriesId: string) => string;
|
|
754
|
+
/**
|
|
755
|
+
* Format the time pill from the bucket's start/end unix seconds. The end is
|
|
756
|
+
* clamped to the chart's current-time anchor, so the live bucket never claims
|
|
757
|
+
* to end in the future. Defaults to two chart `formatTime` labels joined by
|
|
758
|
+
* an en dash.
|
|
759
|
+
*
|
|
760
|
+
* Runs on the UI thread and must be worklet-safe.
|
|
761
|
+
*/
|
|
762
|
+
formatTimeRange?: (from: number, to: number) => string;
|
|
763
|
+
/** Truncate labels longer than this many characters with `…`. Default `14`. */
|
|
764
|
+
maxLabelChars?: number;
|
|
765
|
+
|
|
766
|
+
/** Guide color. Omit to use `scrub.crosshairLineColor`, then the theme. */
|
|
767
|
+
guideColor?: string;
|
|
768
|
+
/** Guide stroke width in px. Default `1`. */
|
|
769
|
+
guideWidth?: number;
|
|
770
|
+
/**
|
|
771
|
+
* Guide dash pattern. `true` uses `[3, 3]`; an array supplies explicit Skia
|
|
772
|
+
* dash intervals; `false` draws a solid guide. Default `[3, 3]`.
|
|
773
|
+
*/
|
|
774
|
+
guideDashPattern?: boolean | number[];
|
|
775
|
+
|
|
776
|
+
/** Time-pill background. Omit to use `scrub.tooltipBackground`, then the theme. */
|
|
777
|
+
timePillBackground?: string;
|
|
778
|
+
/** Time-pill text color. Omit to use `scrub.tooltipColor`, then the theme. */
|
|
779
|
+
timePillColor?: string;
|
|
780
|
+
/** Time-pill border color. Omit to use `scrub.tooltipBorderColor`, then the theme. */
|
|
781
|
+
timePillBorderColor?: string;
|
|
782
|
+
/** Time-pill corner radius in px. Default `6`. */
|
|
783
|
+
timePillRadius?: number;
|
|
784
|
+
/** Time-pill horizontal padding in px. Default `8`. */
|
|
785
|
+
timePillPaddingX?: number;
|
|
786
|
+
/** Time-pill vertical padding in px. Default `4`. */
|
|
787
|
+
timePillPaddingY?: number;
|
|
788
|
+
|
|
789
|
+
/** Series-pill background. Omit to use `scrub.tooltipBackground`, then the theme. */
|
|
790
|
+
seriesPillBackground?: string;
|
|
791
|
+
/** Series label color. Omit to use the theme tooltip text. */
|
|
792
|
+
seriesPillLabelColor?: string;
|
|
793
|
+
/** Formatted series value color. Omit to use `seriesPillLabelColor`. */
|
|
794
|
+
seriesPillValueColor?: string;
|
|
795
|
+
/** Series-pill border color. Omit to use `scrub.tooltipBorderColor`, then the theme. */
|
|
796
|
+
seriesPillBorderColor?: string;
|
|
797
|
+
/** Series-pill corner radius in px. Default `6`. */
|
|
798
|
+
seriesPillRadius?: number;
|
|
799
|
+
/** Series-pill horizontal padding in px. Default `8`. */
|
|
800
|
+
seriesPillPaddingX?: number;
|
|
801
|
+
/** Series-pill vertical padding in px. Default `4`. */
|
|
802
|
+
seriesPillPaddingY?: number;
|
|
803
|
+
/** Diameter of the series-colour dot inside each pill, in px. Default `8`. */
|
|
804
|
+
seriesPillDotSize?: number;
|
|
805
|
+
/** Gap between the colour dot and label, in px. Default `6`. */
|
|
806
|
+
seriesPillDotGap?: number;
|
|
807
|
+
/** Gap between the label and formatted value, in px. Default `6`. */
|
|
808
|
+
seriesPillLabelValueGap?: number;
|
|
809
|
+
/** Diameter of the dot drawn at each line/guide intersection. Default `8`. */
|
|
810
|
+
intersectionDotSize?: number;
|
|
811
|
+
}
|
|
812
|
+
|
|
714
813
|
/** Crosshair scrub configuration. */
|
|
715
814
|
export interface ScrubConfig {
|
|
716
815
|
/** Show the value/time tooltip pill while scrubbing. Default `true`. */
|
|
717
816
|
tooltip?: boolean;
|
|
817
|
+
/**
|
|
818
|
+
* Opt into the Morfi-style per-series pill tooltip on `LiveChartSeries`.
|
|
819
|
+
* `true` uses defaults; an object enables and configures it; `false`/omitted
|
|
820
|
+
* preserves the existing guide-only multi-series scrub. Ignored by
|
|
821
|
+
* single-series `LiveChart`. Default `false`.
|
|
822
|
+
*/
|
|
823
|
+
seriesTooltip?: boolean | PerSeriesTooltipConfig;
|
|
718
824
|
/**
|
|
719
825
|
* Opacity of the chart content to the *right* of the crosshair (the "future")
|
|
720
826
|
* while scrubbing — `0` fully fades it out, `1` disables the dim. Implemented
|
|
@@ -960,7 +1066,8 @@ export interface ChartScale {
|
|
|
960
1066
|
|
|
961
1067
|
/**
|
|
962
1068
|
* The price↔pixel / time↔pixel bridge handed to a custom
|
|
963
|
-
* {@link LiveChartProps.renderOverlay}
|
|
1069
|
+
* {@link LiveChartProps.renderOverlay} or
|
|
1070
|
+
* {@link LiveChartSeriesProps.renderOverlay}.
|
|
964
1071
|
*
|
|
965
1072
|
* **Easiest path — the `usePriceY` / `useTimeX` hooks.** They project a price / time
|
|
966
1073
|
* to a `SharedValue<number>` that tracks the live axis for you; just read it in
|
|
@@ -1122,7 +1229,8 @@ export interface TradeEvent {
|
|
|
1122
1229
|
}
|
|
1123
1230
|
|
|
1124
1231
|
/** Built-in marker glyph kinds drawn into the chart canvas. */
|
|
1125
|
-
export type MarkerKind =
|
|
1232
|
+
export type MarkerKind =
|
|
1233
|
+
"trade" | "boost" | "graduation" | "winner" | "clawback";
|
|
1126
1234
|
|
|
1127
1235
|
/**
|
|
1128
1236
|
* A marker rendered into the chart at `(time, y)`. Exactly one of `seriesId`
|
|
@@ -1614,6 +1722,15 @@ export interface TimeScrollConfig {
|
|
|
1614
1722
|
* if set, otherwise `500`.
|
|
1615
1723
|
*/
|
|
1616
1724
|
scrubHoldMs?: number;
|
|
1725
|
+
/**
|
|
1726
|
+
* Hide the live badge, dot, and dashed value line while scrolled back through
|
|
1727
|
+
* history. Default `true`: all three mark the LIVE price, which is off-screen
|
|
1728
|
+
* once the window is frozen behind the live edge, so they'd point at a price
|
|
1729
|
+
* that isn't in view. Set `false` to keep them visible while scrolled back.
|
|
1730
|
+
* Ignored when `badge.followViewEdge` is on — there the group tracks the
|
|
1731
|
+
* visible edge price, which IS in view.
|
|
1732
|
+
*/
|
|
1733
|
+
hideLiveOnScrollBack?: boolean;
|
|
1617
1734
|
}
|
|
1618
1735
|
|
|
1619
1736
|
/**
|
|
@@ -1748,6 +1865,18 @@ export interface LiveChartCoreProps {
|
|
|
1748
1865
|
insets?: ChartInsets;
|
|
1749
1866
|
/** Container View style. */
|
|
1750
1867
|
style?: ViewStyle;
|
|
1868
|
+
/**
|
|
1869
|
+
* Canvas composition mode. `"transparent"` keeps Skia's default compositing
|
|
1870
|
+
* path (TextureView on Android) and can reveal content behind the chart.
|
|
1871
|
+
* `"opaque"` makes the canvas own and paint its palette background; on Android
|
|
1872
|
+
* this selects SurfaceView and may reduce RenderThread work, but it cannot be
|
|
1873
|
+
* used when the chart must reveal content behind it. Default `"transparent"`.
|
|
1874
|
+
*
|
|
1875
|
+
* @experimental Profile on representative physical Android hardware before
|
|
1876
|
+
* enabling broadly; SurfaceView ordering, clipping, transforms, screenshots,
|
|
1877
|
+
* and parent scrolling should be validated in the consuming layout.
|
|
1878
|
+
*/
|
|
1879
|
+
canvasMode?: CanvasMode;
|
|
1751
1880
|
/** Visible time window in seconds. Default `30`. */
|
|
1752
1881
|
timeWindow?: number;
|
|
1753
1882
|
/** Freeze chart scrolling. Resume catches up to real time. Default `false`. */
|
|
@@ -1990,8 +2119,9 @@ export interface LiveChartCoreProps {
|
|
|
1990
2119
|
*
|
|
1991
2120
|
* Defaults differ per chart: `LiveChart` shows it (`true`); `LiveChartSeries`
|
|
1992
2121
|
* hides it (`false`) — with multiple lines the dot can only track the leading
|
|
1993
|
-
* series
|
|
1994
|
-
* Pass `true` / a config to
|
|
2122
|
+
* series. The crosshair — and, when enabled, the per-series tooltip's own
|
|
2123
|
+
* intersection dots — mark the scrub point instead. Pass `true` / a config to
|
|
2124
|
+
* opt a multi-series chart in.
|
|
1995
2125
|
*/
|
|
1996
2126
|
selectionDot?: boolean | SelectionDotConfig;
|
|
1997
2127
|
/** Called once when the user starts scrubbing/panning the chart. */
|
|
@@ -2143,19 +2273,36 @@ export interface LiveChartProps extends LiveChartCoreProps {
|
|
|
2143
2273
|
* pins it to the line's value on the UI thread (see {@link ReferenceLineRenderProps}),
|
|
2144
2274
|
* so it tracks the rescaling axis and any drag without JS re-renders. Called per
|
|
2145
2275
|
* Form-A line; return `null`/`undefined` to keep that line's built-in tag. Works
|
|
2146
|
-
* with `badge: false` too (replace the plain gutter label).
|
|
2276
|
+
* with `badge: false` too (replace the plain gutter label). For a left- or
|
|
2277
|
+
* right-pinned `badge`, the chart retains the dashed connector and measures the
|
|
2278
|
+
* custom tag so the connector starts at its outer edge. Single-series only.
|
|
2147
2279
|
*/
|
|
2148
2280
|
renderReferenceLine?: (
|
|
2149
2281
|
ctx: ReferenceLineRenderProps,
|
|
2150
2282
|
) => ReactElement | null | undefined;
|
|
2283
|
+
/**
|
|
2284
|
+
* Render only a Form-A line's **off-axis** tag as a custom React Native element.
|
|
2285
|
+
* The chart keeps the standard Skia tag / gutter label while the value is in
|
|
2286
|
+
* range, then switches to this element when it pins above or below the plot.
|
|
2287
|
+
* With a left- or right-pinned `badge` (or legacy `offAxisBadge`), its dashed
|
|
2288
|
+
* connector stays native and begins after the measured custom tag. Return
|
|
2289
|
+
* `null`/`undefined` to opt a line out based on its static `line` / `index`;
|
|
2290
|
+
* use the `edge` SharedValue inside the returned element to animate a caret.
|
|
2291
|
+
* `renderReferenceLine` takes precedence if both callbacks handle one line.
|
|
2292
|
+
* Single-series only.
|
|
2293
|
+
*/
|
|
2294
|
+
renderOffAxisReferenceLine?: (
|
|
2295
|
+
ctx: ReferenceLineRenderProps,
|
|
2296
|
+
) => ReactElement | null | undefined;
|
|
2151
2297
|
/**
|
|
2152
2298
|
* Collapse Form-A reference lines whose handles sit near the same value into a
|
|
2153
2299
|
* single count handle (e.g. a stack of working orders at adjacent prices reads
|
|
2154
2300
|
* as one "×3" tag). `true` = defaults, `false`/omitted = off, or pass a
|
|
2155
2301
|
* {@link ReferenceLineGroupingConfig} to tune the proximity radius. Lines a
|
|
2156
|
-
* {@link LiveChartProps.renderReferenceLine}
|
|
2157
|
-
*
|
|
2158
|
-
* only
|
|
2302
|
+
* {@link LiveChartProps.renderReferenceLine} or
|
|
2303
|
+
* {@link LiveChartProps.renderOffAxisReferenceLine} owns are excluded (their
|
|
2304
|
+
* custom tag draws itself), so the count reflects only collapsed built-in tags.
|
|
2305
|
+
* Single-series only. Default off.
|
|
2159
2306
|
*/
|
|
2160
2307
|
referenceLineGrouping?: boolean | ReferenceLineGroupingConfig;
|
|
2161
2308
|
/**
|
|
@@ -2177,6 +2324,39 @@ export interface LiveChartProps extends LiveChartCoreProps {
|
|
|
2177
2324
|
export interface LiveChartSeriesProps extends LiveChartCoreProps {
|
|
2178
2325
|
/** Array of series definitions. Must be a SharedValue for UI-thread reads. */
|
|
2179
2326
|
series: SharedValue<SeriesConfig[]>;
|
|
2327
|
+
/**
|
|
2328
|
+
* Render a custom overlay floated over the canvas, handed the live
|
|
2329
|
+
* price↔pixel / time↔pixel {@link ChartOverlayContext}. Use its `scale` snapshot
|
|
2330
|
+
* and mapping worklets to position React Native UI against this chart's resolved
|
|
2331
|
+
* plot bounds (including any axis or explicit inset). The tree mounts full-bleed
|
|
2332
|
+
* with `pointerEvents="box-none"`; return `null`/`undefined` for no overlay.
|
|
2333
|
+
*/
|
|
2334
|
+
renderOverlay?: (ctx: ChartOverlayContext) => ReactElement | null | undefined;
|
|
2335
|
+
/**
|
|
2336
|
+
* Render a Form-A reference line's tag as a custom **React Native** element
|
|
2337
|
+
* instead of the built-in Skia pill / gutter label. The chart pins the returned
|
|
2338
|
+
* element to the line's live Y position on the UI thread (see
|
|
2339
|
+
* {@link ReferenceLineRenderProps}), including off-axis edge pinning. Return
|
|
2340
|
+
* `null`/`undefined` to keep that line's built-in tag. The line stroke always
|
|
2341
|
+
* remains visible; a left- or right-pinned badge also keeps its dashed connector,
|
|
2342
|
+
* starting after the measured custom tag. `badge.position` / `labelPosition`
|
|
2343
|
+
* controls the custom tag's left, center, or right anchor.
|
|
2344
|
+
*/
|
|
2345
|
+
renderReferenceLine?: (
|
|
2346
|
+
ctx: ReferenceLineRenderProps,
|
|
2347
|
+
) => ReactElement | null | undefined;
|
|
2348
|
+
/**
|
|
2349
|
+
* Render only a Form-A line's **off-axis** tag as a custom React Native element.
|
|
2350
|
+
* The normal in-range Skia tag / gutter label stays visible, while an edge-pinned
|
|
2351
|
+
* custom tag replaces it above or below the plot. A left- or right-pinned
|
|
2352
|
+
* `badge` (or legacy `offAxisBadge`) retains its native dashed connector, measured
|
|
2353
|
+
* against the custom tag. Return `null`/`undefined` to opt a static `line` /
|
|
2354
|
+
* `index` out; use the `edge` SharedValue inside the returned element to animate
|
|
2355
|
+
* its caret. `renderReferenceLine` takes precedence for the same line.
|
|
2356
|
+
*/
|
|
2357
|
+
renderOffAxisReferenceLine?: (
|
|
2358
|
+
ctx: ReferenceLineRenderProps,
|
|
2359
|
+
) => ReactElement | null | undefined;
|
|
2180
2360
|
/** Called when a series toggle chip is tapped. */
|
|
2181
2361
|
onSeriesToggle?: (id: string, visible: boolean) => void;
|
|
2182
2362
|
/**
|