react-native-livechart 4.2.0 → 4.3.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/dist/components/LiveChart.d.ts.map +1 -1
- package/dist/components/LiveChartSeries.d.ts.map +1 -1
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/liveChartEngineTick.d.ts +11 -0
- package/dist/core/liveChartEngineTick.d.ts.map +1 -1
- package/dist/core/liveChartSeriesEngineTick.d.ts +10 -0
- package/dist/core/liveChartSeriesEngineTick.d.ts.map +1 -1
- package/dist/core/resolveConfig.d.ts +11 -1
- package/dist/core/resolveConfig.d.ts.map +1 -1
- package/dist/core/useLiveChartEngine.d.ts +18 -0
- package/dist/core/useLiveChartEngine.d.ts.map +1 -1
- package/dist/core/useLiveChartSeriesEngine.d.ts +17 -0
- package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -1
- package/dist/hooks/useReferenceDrag.d.ts +12 -4
- package/dist/hooks/useReferenceDrag.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/math/referenceDrag.d.ts +9 -0
- package/dist/math/referenceDrag.d.ts.map +1 -1
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/LiveChart.tsx +35 -22
- package/src/components/LiveChartSeries.tsx +7 -0
- package/src/constants.ts +7 -0
- package/src/core/liveChartEngineTick.ts +42 -7
- package/src/core/liveChartSeriesEngineTick.ts +37 -5
- package/src/core/resolveConfig.ts +21 -0
- package/src/core/useLiveChartEngine.ts +71 -1
- package/src/core/useLiveChartSeriesEngine.ts +65 -1
- package/src/hooks/useReferenceDrag.ts +41 -11
- package/src/index.ts +1 -0
- package/src/math/referenceDrag.ts +19 -0
- package/src/types.ts +37 -0
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
clampToBounds,
|
|
14
14
|
nearestDraggableIndex,
|
|
15
15
|
referenceValueOut,
|
|
16
|
+
resolveDragIntent,
|
|
16
17
|
} from "../math/referenceDrag";
|
|
17
18
|
import { referenceLineForm } from "../math/referenceLines";
|
|
18
19
|
import type { ReferenceLine } from "../types";
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
|
|
25
26
|
/** Vertical reach (px) around a line within which a touch grabs it. */
|
|
26
27
|
const GRAB_SLOP = 14;
|
|
27
|
-
/** Travel (px)
|
|
28
|
+
/** Travel (px) past which a grabbed line starts dragging (in either axis). */
|
|
28
29
|
const DRAG_ACTIVATE_PX = 4;
|
|
29
30
|
|
|
30
31
|
/** Stable empty array so the handle / out-state worklets stay referentially stable
|
|
@@ -40,9 +41,12 @@ const EMPTY: never[] = [];
|
|
|
40
41
|
* and overlays read.
|
|
41
42
|
*
|
|
42
43
|
* The pan uses `manualActivation`: it grabs only when a touch starts within
|
|
43
|
-
* {@link GRAB_SLOP} of a draggable line **
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* {@link GRAB_SLOP} of a draggable line, then **owns** that touch — any drag past
|
|
45
|
+
* {@link DRAG_ACTIVATE_PX} (in either axis) drags the line. A touch off every line
|
|
46
|
+
* fails fast so the chart's other gestures (scrub / scroll) run everywhere else
|
|
47
|
+
* (compose this ahead of them via `Gesture.Exclusive`). Crucially it no longer
|
|
48
|
+
* falls through to scrub on a horizontal start, so a drag begun on a line always
|
|
49
|
+
* wins the race rather than dropping a scrub crosshair (#163).
|
|
46
50
|
*
|
|
47
51
|
* Also fires the per-line drag callbacks: `onChange` (de-duped during drag),
|
|
48
52
|
* `onCommit` (on release), and `onDragIn` / `onDragOut` (value crossing the visible
|
|
@@ -55,7 +59,12 @@ export function useReferenceDrag(
|
|
|
55
59
|
dragValues: SharedValue<number[]>,
|
|
56
60
|
dragActive: SharedValue<boolean[]>,
|
|
57
61
|
enabled: boolean,
|
|
58
|
-
):
|
|
62
|
+
): {
|
|
63
|
+
gesture: ReturnType<typeof Gesture.Pan>;
|
|
64
|
+
/** True when a touch at (x,y) would grab a draggable line — lets the scrub
|
|
65
|
+
* gesture decline that press so it never drops a crosshair on a line (#163). */
|
|
66
|
+
hitTest: (x: number, y: number) => boolean;
|
|
67
|
+
} {
|
|
59
68
|
const anyDraggable =
|
|
60
69
|
enabled &&
|
|
61
70
|
lines.some((l) => l.draggable && referenceLineForm(l) === "line");
|
|
@@ -178,16 +187,22 @@ export function useReferenceDrag(
|
|
|
178
187
|
/* istanbul ignore next -- gesture worklet runs on the UI thread, not in Jest */
|
|
179
188
|
const onTouchesMove = (
|
|
180
189
|
e: { allTouches: { x: number; y: number }[] },
|
|
181
|
-
manager: { activate: () => void
|
|
190
|
+
manager: { activate: () => void },
|
|
182
191
|
) => {
|
|
183
192
|
"worklet";
|
|
184
193
|
if (dragIndex.get() < 0) return;
|
|
185
194
|
const t = e.allTouches[0];
|
|
186
195
|
if (!t) return;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
// A line is grabbed → it owns the touch: any drag past the threshold drags it.
|
|
197
|
+
// We don't fail on horizontal intent (which used to hand the touch to scrub) —
|
|
198
|
+
// that let the scrub crosshair win the race even on a vertical drag started on
|
|
199
|
+
// the line (#163). Scrub / scroll still run off a line's grab band.
|
|
200
|
+
const intent = resolveDragIntent(
|
|
201
|
+
t.x - startX.get(),
|
|
202
|
+
t.y - startY.get(),
|
|
203
|
+
DRAG_ACTIVATE_PX,
|
|
204
|
+
);
|
|
205
|
+
if (intent === "activate") manager.activate();
|
|
191
206
|
};
|
|
192
207
|
|
|
193
208
|
/* istanbul ignore next -- gesture worklet runs on the UI thread, not in Jest */
|
|
@@ -242,7 +257,20 @@ export function useReferenceDrag(
|
|
|
242
257
|
activated.set(false);
|
|
243
258
|
};
|
|
244
259
|
|
|
245
|
-
|
|
260
|
+
// Geometric hit-test shared with the scrub gesture: is (x,y) within reach of a
|
|
261
|
+
// draggable line's handle? The scrub's `onStart` consults this to bail on a
|
|
262
|
+
// press over a line, so it never drops a crosshair there even though it activates
|
|
263
|
+
// independently of this manual-activation pan (the `Exclusive` priority alone
|
|
264
|
+
// doesn't hold scrub back while this gesture is merely pressed). x is unused —
|
|
265
|
+
// a Form-A line spans the full width, so only the y-reach matters.
|
|
266
|
+
/* istanbul ignore next -- worklet, runs on the UI thread */
|
|
267
|
+
const hitTest = (_x: number, y: number): boolean => {
|
|
268
|
+
"worklet";
|
|
269
|
+
if (!anyDraggable) return false;
|
|
270
|
+
return nearestDraggableIndex(handleYs.get(), y, GRAB_SLOP) >= 0;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const gesture = Gesture.Pan()
|
|
246
274
|
.enabled(anyDraggable)
|
|
247
275
|
.maxPointers(1)
|
|
248
276
|
.manualActivation(true)
|
|
@@ -251,4 +279,6 @@ export function useReferenceDrag(
|
|
|
251
279
|
.onStart(onStart)
|
|
252
280
|
.onUpdate(onUpdate)
|
|
253
281
|
.onFinalize(onFinalize);
|
|
282
|
+
|
|
283
|
+
return { gesture, hitTest };
|
|
254
284
|
}
|
package/src/index.ts
CHANGED
|
@@ -43,6 +43,25 @@ export function nearestDraggableIndex(
|
|
|
43
43
|
return best;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a grabbed line's drag intent from the touch travel (px) since the grab.
|
|
48
|
+
* Once a line is grabbed it **owns** the touch: any drag past `threshold` px in
|
|
49
|
+
* either axis activates the drag. We deliberately don't fall through to scrub on
|
|
50
|
+
* horizontal / diagonal intent — that let the scrub crosshair win the race even
|
|
51
|
+
* on a vertical drag started on the line (#163). Returns `"activate"` past the
|
|
52
|
+
* threshold, else `"wait"` (keep the gesture armed for more travel).
|
|
53
|
+
*/
|
|
54
|
+
export function resolveDragIntent(
|
|
55
|
+
dx: number,
|
|
56
|
+
dy: number,
|
|
57
|
+
threshold: number,
|
|
58
|
+
): "activate" | "wait" {
|
|
59
|
+
"worklet";
|
|
60
|
+
return Math.abs(dx) > threshold || Math.abs(dy) > threshold
|
|
61
|
+
? "activate"
|
|
62
|
+
: "wait";
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
/**
|
|
47
66
|
* Whether a line's value sits **outside** its watched interval — the trigger for
|
|
48
67
|
* `onDragOut` / `onDragIn` (edge-detected by the caller). When `bounds` is set the
|
package/src/types.ts
CHANGED
|
@@ -1492,6 +1492,22 @@ export interface TimeScrollConfig {
|
|
|
1492
1492
|
scrubHoldMs?: number;
|
|
1493
1493
|
}
|
|
1494
1494
|
|
|
1495
|
+
/**
|
|
1496
|
+
* Tunes the "return to live" glide — the eased animation that carries the window
|
|
1497
|
+
* back to the live edge when `timeScroll` is switched off while scrolled back. See
|
|
1498
|
+
* {@link TimeScrollConfig.returnToLive}.
|
|
1499
|
+
*
|
|
1500
|
+
* @experimental
|
|
1501
|
+
*/
|
|
1502
|
+
export interface ReturnToLiveConfig {
|
|
1503
|
+
/**
|
|
1504
|
+
* Glide duration in milliseconds. Default `450`. The window decelerates onto the
|
|
1505
|
+
* live edge (ease-out cubic). Lower = snappier; `0` is treated as no animation
|
|
1506
|
+
* (an instant snap).
|
|
1507
|
+
*/
|
|
1508
|
+
duration?: number;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1495
1511
|
/**
|
|
1496
1512
|
* Pinch-to-zoom the visible time window (see {@link LiveChartCoreProps.zoom}).
|
|
1497
1513
|
*
|
|
@@ -1683,6 +1699,11 @@ export interface LiveChartCoreProps {
|
|
|
1683
1699
|
* live edge again. One-finger plot-area scrub is unchanged. Requires retained
|
|
1684
1700
|
* history in `data` / `candles` to scroll into.
|
|
1685
1701
|
*
|
|
1702
|
+
* Setting this back to `false` while scrolled back — or switching `mode` so it's
|
|
1703
|
+
* no longer passed — **glides** the window back to the live edge (a brief eased
|
|
1704
|
+
* animation, not an instant jump); it never stays frozen at the previous scroll
|
|
1705
|
+
* position. Tune or disable that glide with {@link returnToLive}.
|
|
1706
|
+
*
|
|
1686
1707
|
* `true` uses the default drag-to-scroll gesture (`"holdToScrub"`); pass a
|
|
1687
1708
|
* {@link TimeScrollConfig} to pick the activation (`"holdToScrub"` or
|
|
1688
1709
|
* `"axisDrag"`). Default `false`.
|
|
@@ -1690,6 +1711,22 @@ export interface LiveChartCoreProps {
|
|
|
1690
1711
|
* @experimental Prototype — gesture model and API may change.
|
|
1691
1712
|
*/
|
|
1692
1713
|
timeScroll?: boolean | TimeScrollConfig;
|
|
1714
|
+
/**
|
|
1715
|
+
* Controls the **return-to-live glide** — the animation that carries the window
|
|
1716
|
+
* back to the live edge when {@link timeScroll} is switched off (set to `false`,
|
|
1717
|
+
* or a `mode` switch stops passing it) while scrolled back into history:
|
|
1718
|
+
* - `true` (default) — glide back, easing onto the live edge over `450` ms.
|
|
1719
|
+
* - `false` — snap instantly, no animation.
|
|
1720
|
+
* - {@link ReturnToLiveConfig} — glide with a custom `{ duration }` (ms).
|
|
1721
|
+
*
|
|
1722
|
+
* Kept separate from {@link timeScroll} on purpose: the common way to leave
|
|
1723
|
+
* time-scroll (`timeScroll={false}`) discards any `TimeScrollConfig`, so this
|
|
1724
|
+
* lives alongside it to stay in effect through the toggle. Only governs that
|
|
1725
|
+
* programmatic return; a finger fling back to live keeps its own inertia.
|
|
1726
|
+
*
|
|
1727
|
+
* @experimental
|
|
1728
|
+
*/
|
|
1729
|
+
returnToLive?: boolean | ReturnToLiveConfig;
|
|
1693
1730
|
/**
|
|
1694
1731
|
* Pinch-to-zoom the visible time window. Two-finger pinch in/out narrows or
|
|
1695
1732
|
* widens the window, anchored at the focal point between your fingers. Composes
|