react-native-livechart 4.2.0 → 4.2.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/LiveChart.d.ts.map +1 -1
- package/dist/hooks/useReferenceDrag.d.ts +12 -4
- package/dist/hooks/useReferenceDrag.d.ts.map +1 -1
- package/dist/math/referenceDrag.d.ts +9 -0
- package/dist/math/referenceDrag.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/LiveChart.tsx +22 -20
- package/src/hooks/useReferenceDrag.ts +41 -11
- package/src/math/referenceDrag.ts +19 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveChart.d.ts","sourceRoot":"","sources":["../../src/components/LiveChart.tsx"],"names":[],"mappings":"AAqGA,OAAO,KAAK,EAEV,cAAc,EAGf,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveChart.d.ts","sourceRoot":"","sources":["../../src/components/LiveChart.tsx"],"names":[],"mappings":"AAqGA,OAAO,KAAK,EAEV,cAAc,EAGf,MAAM,UAAU,CAAC;AAuqDlB,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAmK9C"}
|
|
@@ -12,13 +12,21 @@ import type { ReferenceLine } from "../types";
|
|
|
12
12
|
* and overlays read.
|
|
13
13
|
*
|
|
14
14
|
* The pan uses `manualActivation`: it grabs only when a touch starts within
|
|
15
|
-
* {@link GRAB_SLOP} of a draggable line **
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* {@link GRAB_SLOP} of a draggable line, then **owns** that touch — any drag past
|
|
16
|
+
* {@link DRAG_ACTIVATE_PX} (in either axis) drags the line. A touch off every line
|
|
17
|
+
* fails fast so the chart's other gestures (scrub / scroll) run everywhere else
|
|
18
|
+
* (compose this ahead of them via `Gesture.Exclusive`). Crucially it no longer
|
|
19
|
+
* falls through to scrub on a horizontal start, so a drag begun on a line always
|
|
20
|
+
* wins the race rather than dropping a scrub crosshair (#163).
|
|
18
21
|
*
|
|
19
22
|
* Also fires the per-line drag callbacks: `onChange` (de-duped during drag),
|
|
20
23
|
* `onCommit` (on release), and `onDragIn` / `onDragOut` (value crossing the visible
|
|
21
24
|
* range or a `bounds`, from a drag or the axis rescaling — edge-detected each frame).
|
|
22
25
|
*/
|
|
23
|
-
export declare function useReferenceDrag(engine: ChartEngineLayout, padding: ChartPadding, lines: ReferenceLine[], dragValues: SharedValue<number[]>, dragActive: SharedValue<boolean[]>, enabled: boolean):
|
|
26
|
+
export declare function useReferenceDrag(engine: ChartEngineLayout, padding: ChartPadding, lines: ReferenceLine[], dragValues: SharedValue<number[]>, dragActive: SharedValue<boolean[]>, enabled: boolean): {
|
|
27
|
+
gesture: ReturnType<typeof Gesture.Pan>;
|
|
28
|
+
/** True when a touch at (x,y) would grab a draggable line — lets the scrub
|
|
29
|
+
* gesture decline that press so it never drops a crosshair on a line (#163). */
|
|
30
|
+
hitTest: (x: number, y: number) => boolean;
|
|
31
|
+
};
|
|
24
32
|
//# sourceMappingURL=useReferenceDrag.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useReferenceDrag.d.ts","sourceRoot":"","sources":["../../src/hooks/useReferenceDrag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"useReferenceDrag.d.ts","sourceRoot":"","sources":["../../src/hooks/useReferenceDrag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAQjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAgB9C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,aAAa,EAAE,EACtB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,EACjC,UAAU,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAClC,OAAO,EAAE,OAAO,GACf;IACD,OAAO,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACxC;qFACiF;IACjF,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,CAyNA"}
|
|
@@ -13,6 +13,15 @@ export declare function clampToBounds(value: number, bounds?: [number, number]):
|
|
|
13
13
|
* out) are skipped. Ties favor the later (topmost-drawn) line.
|
|
14
14
|
*/
|
|
15
15
|
export declare function nearestDraggableIndex(handleYs: number[], y: number, slop: number): number;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a grabbed line's drag intent from the touch travel (px) since the grab.
|
|
18
|
+
* Once a line is grabbed it **owns** the touch: any drag past `threshold` px in
|
|
19
|
+
* either axis activates the drag. We deliberately don't fall through to scrub on
|
|
20
|
+
* horizontal / diagonal intent — that let the scrub crosshair win the race even
|
|
21
|
+
* on a vertical drag started on the line (#163). Returns `"activate"` past the
|
|
22
|
+
* threshold, else `"wait"` (keep the gesture armed for more travel).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveDragIntent(dx: number, dy: number, threshold: number): "activate" | "wait";
|
|
16
25
|
/**
|
|
17
26
|
* Whether a line's value sits **outside** its watched interval — the trigger for
|
|
18
27
|
* `onDragOut` / `onDragIn` (edge-detected by the caller). When `bounds` is set the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"referenceDrag.d.ts","sourceRoot":"","sources":["../../src/math/referenceDrag.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;2BAC2B;AAC3B,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACxB,MAAM,CAMR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAAE,EAClB,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,GACX,MAAM,CAcR;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACxB,OAAO,CAQT"}
|
|
1
|
+
{"version":3,"file":"referenceDrag.d.ts","sourceRoot":"","sources":["../../src/math/referenceDrag.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;2BAC2B;AAC3B,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACxB,MAAM,CAMR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAAE,EAClB,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,GACX,MAAM,CAcR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,MAAM,CAKrB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACxB,OAAO,CAQT"}
|
package/package.json
CHANGED
|
@@ -798,13 +798,30 @@ function useLiveChartController({
|
|
|
798
798
|
dragValues,
|
|
799
799
|
);
|
|
800
800
|
|
|
801
|
-
//
|
|
802
|
-
//
|
|
803
|
-
//
|
|
801
|
+
// Draggable reference lines: a per-line vertical pan that grabs a line near its
|
|
802
|
+
// value and drags it along the Y-axis (with snap / bounds / callbacks). Built
|
|
803
|
+
// unconditionally for stable hook order (and before `useCrosshair` so the scrub
|
|
804
|
+
// can defer to a line under the finger); the gesture self-disables when no line
|
|
805
|
+
// opts in, and it's only composed into the root when `refDragEnabled`.
|
|
806
|
+
const refDragEnabled =
|
|
807
|
+
!isStatic && allRefLines.some((l) => l.draggable === true);
|
|
808
|
+
const { gesture: refDragGesture, hitTest: refDragHitTest } = useReferenceDrag(
|
|
809
|
+
engine,
|
|
810
|
+
effectivePadding,
|
|
811
|
+
allRefLines,
|
|
812
|
+
dragValues,
|
|
813
|
+
dragActive,
|
|
814
|
+
!isStatic,
|
|
815
|
+
);
|
|
816
|
+
|
|
817
|
+
// Combined "defer" hit-test: the scrub-action place-tap and the live scrub both
|
|
818
|
+
// yield to a marker, a pressable badge, or a draggable line under the finger — so
|
|
819
|
+
// a press there is routed to that overlay / drag instead of dropping a reticle or
|
|
820
|
+
// crosshair. (Each hit-test returns false when its feature is off.)
|
|
804
821
|
/* istanbul ignore next -- worklet runs on the UI thread, not in Jest */
|
|
805
822
|
const deferTapHit = (x: number, y: number): boolean => {
|
|
806
823
|
"worklet";
|
|
807
|
-
return markerHitTest(x, y) || refLineHitTest(x, y);
|
|
824
|
+
return markerHitTest(x, y) || refLineHitTest(x, y) || refDragHitTest(x, y);
|
|
808
825
|
};
|
|
809
826
|
|
|
810
827
|
// Time-scroll activation. `holdToScrub`: a quick one-finger drag scrolls while
|
|
@@ -843,7 +860,7 @@ function useLiveChartController({
|
|
|
843
860
|
scrubActionCfg,
|
|
844
861
|
onScrubAction,
|
|
845
862
|
metricsCfg.badge,
|
|
846
|
-
markersActive || refPressActive ? deferTapHit : undefined,
|
|
863
|
+
markersActive || refPressActive || refDragEnabled ? deferTapHit : undefined,
|
|
847
864
|
scrubCfg?.tooltipPlacement ?? "side",
|
|
848
865
|
scrubCfg?.tooltipShowValue ?? true,
|
|
849
866
|
scrubCfg?.tooltipShowTime ?? true,
|
|
@@ -876,21 +893,6 @@ function useLiveChartController({
|
|
|
876
893
|
},
|
|
877
894
|
});
|
|
878
895
|
|
|
879
|
-
// Draggable reference lines: a per-line vertical pan that grabs a line near its
|
|
880
|
-
// value and drags it along the Y-axis (with snap / bounds / callbacks). Built
|
|
881
|
-
// unconditionally for stable hook order; the gesture self-disables when no line
|
|
882
|
-
// opts in, and it's only composed into the root when `refDragEnabled`.
|
|
883
|
-
const refDragEnabled =
|
|
884
|
-
!isStatic && allRefLines.some((l) => l.draggable === true);
|
|
885
|
-
const refDragGesture = useReferenceDrag(
|
|
886
|
-
engine,
|
|
887
|
-
effectivePadding,
|
|
888
|
-
allRefLines,
|
|
889
|
-
dragValues,
|
|
890
|
-
dragActive,
|
|
891
|
-
!isStatic,
|
|
892
|
-
);
|
|
893
|
-
|
|
894
896
|
// Pinch-to-zoom the visible window (two-finger). Anchors at the focal point and
|
|
895
897
|
// writes viewWindow + viewEnd; composes via Simultaneous (it's two-finger, so
|
|
896
898
|
// disjoint from the one-finger pan/scrub). See `zoom`.
|
|
@@ -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
|
}
|
|
@@ -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
|