@react-native-ohos/victory-native-xl 41.17.5 → 41.18.0-beta.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/README.md +1 -1
- package/package.json +6 -3
- package/src/cartesian/CartesianChart.tsx +130 -44
- package/src/index.ts +6 -2
- package/src/polar/PolarChart.tsx +4 -2
- package/src/shared/GestureHandler.tsx +45 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @react-native-ohos/victory-native-xl
|
|
2
2
|
|
|
3
|
-
本项目基于 [victory-native-xl@v41.
|
|
3
|
+
本项目基于 [victory-native-xl@v41.20.2](https://github.com/FormidableLabs/victory-native-xl/tree/victory-native%4041.20.2)
|
|
4
4
|
|
|
5
5
|
## 文档地址 / Documentation URL
|
|
6
6
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-ohos/victory-native-xl",
|
|
3
|
-
"version": "41.
|
|
3
|
+
"version": "41.18.0-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,9 +24,11 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"d3-scale": "^4.0.2",
|
|
26
26
|
"d3-shape": "^3.2.0",
|
|
27
|
+
"d3-zoom": "^3.0.0",
|
|
27
28
|
"its-fine": "^1.2.5",
|
|
28
29
|
"react-fast-compare": "^3.2.2",
|
|
29
|
-
"react-native-reanimated": "3.18.0"
|
|
30
|
+
"react-native-reanimated": "3.18.0",
|
|
31
|
+
"victory-native": "41.20.2"
|
|
30
32
|
},
|
|
31
33
|
"peerDependencies": {
|
|
32
34
|
"@react-native-ohos/react-native-skia": "file:packages/react-native-ohos-react-native-skia-1.3.7.tgz",
|
|
@@ -34,7 +36,8 @@
|
|
|
34
36
|
"@react-native-ohos/react-native-reanimated": "file:packages/react-native-ohos-react-native-reanimated-3.18.0.tgz",
|
|
35
37
|
"@shopify/react-native-skia": "^1.3.7",
|
|
36
38
|
"react": "18.3.1",
|
|
37
|
-
"react-native": "0.77.1"
|
|
39
|
+
"react-native": "0.77.1",
|
|
40
|
+
"victory-native": "41.20.2"
|
|
38
41
|
},
|
|
39
42
|
"devDependencies": {
|
|
40
43
|
"@types/d3-scale": "^4.0.3",
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { type LayoutChangeEvent
|
|
3
|
-
import { Canvas, Group,
|
|
4
|
-
import { useSharedValue } from "react-native-reanimated";
|
|
2
|
+
import { View, type LayoutChangeEvent } from "react-native";
|
|
3
|
+
import { Canvas, Group, type CanvasRef } from "@shopify/react-native-skia";
|
|
4
|
+
import { useSharedValue, useAnimatedReaction, runOnJS } from "react-native-reanimated";
|
|
5
5
|
import {
|
|
6
6
|
type ComposedGesture,
|
|
7
7
|
Gesture,
|
|
8
|
-
GestureDetector,
|
|
9
8
|
GestureHandlerRootView,
|
|
10
9
|
type TouchData,
|
|
11
10
|
} from "react-native-gesture-handler";
|
|
12
11
|
import { type MutableRefObject } from "react";
|
|
13
|
-
import
|
|
12
|
+
import { ZoomTransform } from "d3-zoom";
|
|
13
|
+
import type { ScaleLinear, ScaleLogarithmic } from "d3-scale";
|
|
14
|
+
import isEqual from "react-fast-compare";
|
|
14
15
|
import type {
|
|
15
16
|
AxisProps,
|
|
16
17
|
CartesianChartRenderArg,
|
|
@@ -19,23 +20,21 @@ import type {
|
|
|
19
20
|
SidedNumber,
|
|
20
21
|
TransformedData,
|
|
21
22
|
ChartBounds,
|
|
22
|
-
Viewport,
|
|
23
|
-
ChartPressPanConfig,
|
|
24
23
|
YAxisInputProps,
|
|
25
|
-
FrameInputProps,
|
|
26
24
|
XAxisInputProps,
|
|
27
|
-
|
|
25
|
+
FrameInputProps,
|
|
26
|
+
ChartPressPanConfig,
|
|
27
|
+
Viewport,
|
|
28
|
+
GestureHandlerConfig,
|
|
28
29
|
} from "victory-native/src/types";
|
|
29
30
|
import { transformInputData } from "victory-native/src/cartesian/utils/transformInputData";
|
|
30
31
|
import { findClosestPoint } from "victory-native/src/utils/findClosestPoint";
|
|
31
32
|
import { valueFromSidedNumber } from "victory-native/src/utils/valueFromSidedNumber";
|
|
32
|
-
import {
|
|
33
|
-
CartesianAxis,
|
|
34
|
-
CartesianAxisDefaultProps,
|
|
35
|
-
} from "victory-native/src/cartesian/components/CartesianAxis";
|
|
36
33
|
import { asNumber } from "victory-native/src/utils/asNumber";
|
|
37
|
-
import type {
|
|
38
|
-
|
|
34
|
+
import type {
|
|
35
|
+
ChartPressState,
|
|
36
|
+
ChartPressStateInit,
|
|
37
|
+
} from "victory-native/src/cartesian/hooks/useChartPressState";
|
|
39
38
|
import { useFunctionRef } from "victory-native/src/hooks/useFunctionRef";
|
|
40
39
|
import { CartesianChartProvider } from "victory-native/src/cartesian/contexts/CartesianChartContext";
|
|
41
40
|
import { XAxis } from "victory-native/src/cartesian/components/XAxis";
|
|
@@ -54,12 +53,11 @@ import {
|
|
|
54
53
|
useCartesianTransformContext,
|
|
55
54
|
} from "victory-native/src/cartesian/contexts/CartesianTransformContext";
|
|
56
55
|
import { downsampleTicks } from "victory-native/src/utils/tickHelpers";
|
|
57
|
-
import { GestureHandler } from "
|
|
56
|
+
import { GestureHandler } from "../shared/GestureHandler";
|
|
58
57
|
import { boundsToClip } from "victory-native/src/utils/boundsToClip";
|
|
59
58
|
import { normalizeYAxisTicks } from "victory-native/src/utils/normalizeYAxisTicks";
|
|
60
59
|
import { createFallbackChartState } from "victory-native/src/cartesian/utils/createFallbackChartState";
|
|
61
|
-
|
|
62
|
-
import isEqual from "react-fast-compare";
|
|
60
|
+
|
|
63
61
|
export type CartesianActionsHandle<T = undefined> =
|
|
64
62
|
T extends ChartPressState<infer S>
|
|
65
63
|
? S extends ChartPressStateInit
|
|
@@ -69,6 +67,11 @@ export type CartesianActionsHandle<T = undefined> =
|
|
|
69
67
|
: never
|
|
70
68
|
: never;
|
|
71
69
|
|
|
70
|
+
export type CartesianChartRef<T = undefined> = {
|
|
71
|
+
canvas: CanvasRef | null;
|
|
72
|
+
actions: CartesianActionsHandle<T>;
|
|
73
|
+
};
|
|
74
|
+
|
|
72
75
|
type CartesianChartProps<
|
|
73
76
|
RawData extends Record<string, unknown>,
|
|
74
77
|
XK extends keyof InputFields<RawData>,
|
|
@@ -93,7 +96,6 @@ type CartesianChartProps<
|
|
|
93
96
|
args: CartesianChartRenderArg<RawData, YK>,
|
|
94
97
|
) => React.ReactNode;
|
|
95
98
|
axisOptions?: Partial<Omit<AxisProps<RawData, XK, YK>, "xScale" | "yScale">>;
|
|
96
|
-
|
|
97
99
|
onChartBoundsChange?: (bounds: ChartBounds) => void;
|
|
98
100
|
onScaleChange?: (
|
|
99
101
|
xScale: ScaleLinear<number, number>,
|
|
@@ -111,6 +113,8 @@ type CartesianChartProps<
|
|
|
111
113
|
pan?: PanTransformGestureConfig;
|
|
112
114
|
pinch?: PinchTransformGestureConfig;
|
|
113
115
|
};
|
|
116
|
+
/** Optional hook for ScrollView coordination (e.g. disable scroll on pan/pinch). */
|
|
117
|
+
onTransformInteractionChange?: (active: boolean) => void;
|
|
114
118
|
customGestures?: ComposedGesture;
|
|
115
119
|
actionsRef?: MutableRefObject<CartesianActionsHandle<
|
|
116
120
|
| ChartPressState<{
|
|
@@ -119,16 +123,30 @@ type CartesianChartProps<
|
|
|
119
123
|
}>
|
|
120
124
|
| undefined
|
|
121
125
|
> | null>;
|
|
126
|
+
ref?: React.Ref<
|
|
127
|
+
CartesianChartRef<
|
|
128
|
+
| ChartPressState<{
|
|
129
|
+
x: InputFields<RawData>[XK];
|
|
130
|
+
y: Record<YK, number>;
|
|
131
|
+
}>
|
|
132
|
+
| undefined
|
|
133
|
+
>
|
|
134
|
+
>;
|
|
122
135
|
};
|
|
123
136
|
|
|
124
137
|
export function CartesianChart<
|
|
125
138
|
RawData extends Record<string, unknown>,
|
|
126
139
|
XK extends keyof InputFields<RawData>,
|
|
127
140
|
YK extends keyof NumericalFields<RawData>,
|
|
128
|
-
>({
|
|
141
|
+
>({
|
|
142
|
+
transformState,
|
|
143
|
+
children,
|
|
144
|
+
ref,
|
|
145
|
+
...rest
|
|
146
|
+
}: CartesianChartProps<RawData, XK, YK>) {
|
|
129
147
|
return (
|
|
130
148
|
<CartesianTransformProvider transformState={transformState}>
|
|
131
|
-
<CartesianChartContent {...{ ...rest, transformState }}>
|
|
149
|
+
<CartesianChartContent {...{ ...rest, transformState }} ref={ref}>
|
|
132
150
|
{children}
|
|
133
151
|
</CartesianChartContent>
|
|
134
152
|
</CartesianTransformProvider>
|
|
@@ -160,18 +178,43 @@ function CartesianChartContent<
|
|
|
160
178
|
frame,
|
|
161
179
|
transformState,
|
|
162
180
|
transformConfig,
|
|
181
|
+
onTransformInteractionChange,
|
|
163
182
|
customGestures,
|
|
164
183
|
actionsRef,
|
|
165
184
|
viewport,
|
|
185
|
+
ref,
|
|
166
186
|
}: CartesianChartProps<RawData, XK, YK>) {
|
|
187
|
+
const onTransformInteractionChangeRef = useFunctionRef(
|
|
188
|
+
onTransformInteractionChange,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
useAnimatedReaction(
|
|
192
|
+
() =>
|
|
193
|
+
transformState
|
|
194
|
+
? transformState.panActive.value || transformState.zoomActive.value
|
|
195
|
+
: false,
|
|
196
|
+
(active, prev) => {
|
|
197
|
+
if (
|
|
198
|
+
!onTransformInteractionChangeRef.current ||
|
|
199
|
+
prev === null ||
|
|
200
|
+
active === prev
|
|
201
|
+
) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
runOnJS(onTransformInteractionChangeRef.current)(active);
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
167
208
|
const [size, setSize] = React.useState({ width: 0, height: 0 });
|
|
168
209
|
const chartBoundsRef = React.useRef<ChartBounds | undefined>(undefined);
|
|
169
|
-
const xScaleRef = React.useRef<
|
|
170
|
-
undefined
|
|
171
|
-
);
|
|
210
|
+
const xScaleRef = React.useRef<
|
|
211
|
+
ScaleLogarithmic<number, number> | ScaleLinear<number, number> | undefined
|
|
212
|
+
>(undefined);
|
|
213
|
+
|
|
172
214
|
const yScaleRef = React.useRef<ScaleLinear<number, number> | undefined>(
|
|
173
215
|
undefined,
|
|
174
216
|
);
|
|
217
|
+
const canvasRef = React.useRef<CanvasRef | null>(null);
|
|
175
218
|
const [hasMeasuredLayoutSize, setHasMeasuredLayoutSize] =
|
|
176
219
|
React.useState(false);
|
|
177
220
|
const onLayout = React.useCallback(
|
|
@@ -241,6 +284,7 @@ function CartesianChartContent<
|
|
|
241
284
|
yAxes: normalizedAxisProps.yAxes,
|
|
242
285
|
viewport,
|
|
243
286
|
labelRotate: normalizedAxisProps.xAxis.labelRotate,
|
|
287
|
+
axisScales: axisOptions?.axisScales,
|
|
244
288
|
});
|
|
245
289
|
|
|
246
290
|
const primaryYAxis = yAxes[0];
|
|
@@ -298,7 +342,10 @@ function CartesianChartContent<
|
|
|
298
342
|
* Take a "press value" and an x-value and update the shared values accordingly.
|
|
299
343
|
*/
|
|
300
344
|
const handleTouch = (
|
|
301
|
-
v: ChartPressState<{
|
|
345
|
+
v: ChartPressState<{
|
|
346
|
+
x: InputFields<RawData>[XK];
|
|
347
|
+
y: Record<YK, number>;
|
|
348
|
+
}>,
|
|
302
349
|
x: number,
|
|
303
350
|
y: number,
|
|
304
351
|
) => {
|
|
@@ -308,7 +355,6 @@ function CartesianChartContent<
|
|
|
308
355
|
if (typeof idx !== "number") return;
|
|
309
356
|
|
|
310
357
|
const isInYs = (yk: string): yk is YK & string => yKeys.includes(yk as YK);
|
|
311
|
-
|
|
312
358
|
// begin stacked bar handling:
|
|
313
359
|
// store the heights of each bar segment
|
|
314
360
|
const barHeights: number[] = [];
|
|
@@ -363,6 +409,18 @@ function CartesianChartContent<
|
|
|
363
409
|
lastIdx.value = idx;
|
|
364
410
|
};
|
|
365
411
|
|
|
412
|
+
React.useImperativeHandle(
|
|
413
|
+
ref,
|
|
414
|
+
() => ({
|
|
415
|
+
canvas: canvasRef.current,
|
|
416
|
+
actions: {
|
|
417
|
+
handleTouch,
|
|
418
|
+
},
|
|
419
|
+
}),
|
|
420
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
421
|
+
[canvasRef],
|
|
422
|
+
);
|
|
423
|
+
|
|
366
424
|
if (actionsRef) {
|
|
367
425
|
actionsRef.current = {
|
|
368
426
|
handleTouch,
|
|
@@ -410,7 +468,16 @@ function CartesianChartContent<
|
|
|
410
468
|
touchMap.value[touch.id] = i;
|
|
411
469
|
|
|
412
470
|
v.isActive.value = true;
|
|
413
|
-
|
|
471
|
+
|
|
472
|
+
// [3] and [7] are the X and Y translation components of the 4x4 transformation matrix, respectively.
|
|
473
|
+
const scrolledX = transformState?.matrix.value?.[3] || 0;
|
|
474
|
+
const scrolledY = transformState?.matrix.value?.[7] || 0;
|
|
475
|
+
|
|
476
|
+
handleTouch(
|
|
477
|
+
v,
|
|
478
|
+
touch.absoluteX - scrolledX,
|
|
479
|
+
touch.absoluteY - scrolledY,
|
|
480
|
+
);
|
|
414
481
|
} else {
|
|
415
482
|
gestureState.value.bootstrap.push([v, touch]);
|
|
416
483
|
}
|
|
@@ -429,7 +496,15 @@ function CartesianChartContent<
|
|
|
429
496
|
touchMap.value[touch.id] = i;
|
|
430
497
|
|
|
431
498
|
v.isActive.value = true;
|
|
432
|
-
|
|
499
|
+
|
|
500
|
+
const scrolledX = transformState?.matrix.value?.[3] || 0;
|
|
501
|
+
const scrolledY = transformState?.matrix.value?.[7] || 0;
|
|
502
|
+
|
|
503
|
+
handleTouch(
|
|
504
|
+
v,
|
|
505
|
+
touch.absoluteX - scrolledX,
|
|
506
|
+
touch.absoluteY - scrolledY,
|
|
507
|
+
);
|
|
433
508
|
}
|
|
434
509
|
})
|
|
435
510
|
/**
|
|
@@ -454,7 +529,15 @@ function CartesianChartContent<
|
|
|
454
529
|
|
|
455
530
|
if (!v || !touch) continue;
|
|
456
531
|
if (!v.isActive.value) v.isActive.value = true;
|
|
457
|
-
|
|
532
|
+
|
|
533
|
+
const scrolledX = transformState?.matrix.value?.[3] || 0;
|
|
534
|
+
const scrolledY = transformState?.matrix.value?.[7] || 0;
|
|
535
|
+
|
|
536
|
+
handleTouch(
|
|
537
|
+
v,
|
|
538
|
+
touch.absoluteX - scrolledX,
|
|
539
|
+
touch.absoluteY - scrolledY,
|
|
540
|
+
);
|
|
458
541
|
}
|
|
459
542
|
})
|
|
460
543
|
/**
|
|
@@ -650,7 +733,7 @@ function CartesianChartContent<
|
|
|
650
733
|
|
|
651
734
|
// Body of the chart.
|
|
652
735
|
const body = (
|
|
653
|
-
<Canvas style={{ flex: 1 }}
|
|
736
|
+
<Canvas ref={canvasRef} style={{ flex: 1 }}>
|
|
654
737
|
{YAxisComponents}
|
|
655
738
|
{XAxisComponents}
|
|
656
739
|
{FrameComponent}
|
|
@@ -690,20 +773,23 @@ function CartesianChartContent<
|
|
|
690
773
|
}
|
|
691
774
|
|
|
692
775
|
return (
|
|
693
|
-
<GestureHandlerRootView style={{ flex: 1
|
|
694
|
-
{
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
776
|
+
<GestureHandlerRootView style={{ flex: 1}}>
|
|
777
|
+
<View style={{ flex: 1, overflow: "hidden" }} onLayout={onLayout}>
|
|
778
|
+
{body}
|
|
779
|
+
<GestureHandler
|
|
780
|
+
config={gestureHandlerConfig}
|
|
781
|
+
gesture={composed}
|
|
782
|
+
transformState={transformState}
|
|
783
|
+
dimensions={{
|
|
784
|
+
x: Math.min(xScale.range()[0]!, 0),
|
|
785
|
+
y: Math.min(primaryYScale.range()[0]!, 0),
|
|
786
|
+
width: xScale.range()[1]! - Math.min(xScale.range()[0]!, 0),
|
|
787
|
+
height:
|
|
788
|
+
primaryYScale.range()[1]! -
|
|
789
|
+
Math.min(primaryYScale.range()[0]!, 0),
|
|
790
|
+
}}
|
|
791
|
+
/>
|
|
792
|
+
</View>
|
|
707
793
|
</GestureHandlerRootView>
|
|
708
794
|
);
|
|
709
795
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cartesian chart exports (including useful types)
|
|
3
3
|
*/
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
CartesianChart,
|
|
6
|
+
type CartesianActionsHandle,
|
|
7
|
+
type CartesianChartRef,
|
|
8
|
+
} from "./cartesian/CartesianChart";
|
|
5
9
|
export { PolarChart } from "./polar/PolarChart";
|
|
6
10
|
|
|
7
|
-
|
|
8
11
|
export { type CurveType } from "victory-native";
|
|
9
12
|
export { type RoundedCorners } from "victory-native";
|
|
13
|
+
export { type AxisScaleType, type AxisScales } from "victory-native/src/types";
|
|
10
14
|
|
|
11
15
|
export { useAnimatedPath } from "victory-native";
|
|
12
16
|
export { AnimatedPath } from "victory-native";
|
package/src/polar/PolarChart.tsx
CHANGED
|
@@ -52,9 +52,11 @@ const PolarChartBase = (
|
|
|
52
52
|
const ctx = usePolarChartContext();
|
|
53
53
|
const ContextBridge = useContextBridge();
|
|
54
54
|
return (
|
|
55
|
-
<View
|
|
55
|
+
<View
|
|
56
|
+
style={[styles.baseContainer, containerStyle]}
|
|
57
|
+
onLayout={onLayout}
|
|
58
|
+
>
|
|
56
59
|
<Canvas
|
|
57
|
-
onLayout={onLayout}
|
|
58
60
|
style={StyleSheet.flatten([
|
|
59
61
|
styles.canvasContainer,
|
|
60
62
|
hasMeasuredLayoutSize ? { width, height } : null,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ComposedGesture,
|
|
3
|
+
GestureDetector,
|
|
4
|
+
type GestureType,
|
|
5
|
+
} from "react-native-gesture-handler";
|
|
6
|
+
import { type SkRect } from "@shopify/react-native-skia";
|
|
7
|
+
import Animated, { useAnimatedStyle } from "react-native-reanimated";
|
|
8
|
+
import * as React from "react";
|
|
9
|
+
import { type ChartTransformState } from "victory-native/src/cartesian/hooks/useChartTransformState";
|
|
10
|
+
import type { GestureHandlerConfig } from "victory-native/src/types";
|
|
11
|
+
|
|
12
|
+
type GestureHandlerProps = {
|
|
13
|
+
gesture: ComposedGesture | GestureType;
|
|
14
|
+
dimensions?: SkRect;
|
|
15
|
+
transformState?: ChartTransformState;
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
config?: GestureHandlerConfig;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* OHOS: Keep the gesture overlay fixed to the chart container instead of
|
|
22
|
+
* following transformState.matrix. Upstream 41.20.2 moves the overlay with
|
|
23
|
+
* matrix transforms, which breaks pan/pinch on HarmonyOS RNGH (e.g. Y pan
|
|
24
|
+
* requires a horizontal move first). Aligns with upstream main PR #664.
|
|
25
|
+
*/
|
|
26
|
+
export const GestureHandler = ({
|
|
27
|
+
gesture,
|
|
28
|
+
debug = false,
|
|
29
|
+
config,
|
|
30
|
+
}: GestureHandlerProps) => {
|
|
31
|
+
const style = useAnimatedStyle(() => ({
|
|
32
|
+
position: "absolute",
|
|
33
|
+
top: 0,
|
|
34
|
+
left: 0,
|
|
35
|
+
right: 0,
|
|
36
|
+
bottom: 0,
|
|
37
|
+
backgroundColor: debug ? "rgba(100, 200, 255, 0.4)" : "transparent",
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<GestureDetector {...config} gesture={gesture}>
|
|
42
|
+
<Animated.View style={style} />
|
|
43
|
+
</GestureDetector>
|
|
44
|
+
);
|
|
45
|
+
};
|