Skip to content

Commit bb6c159

Browse files
committed
fix and simplify arrow coordinate system
1 parent c27a0f3 commit bb6c159

2 files changed

Lines changed: 57 additions & 48 deletions

File tree

packages/docs-gesture-handler/src/examples/GestureStateFlowExample/ChartItem.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
import { Grid } from '@mui/material';
2-
import { useEffect } from 'react';
3-
import { StyleProp, StyleSheet, View, Text, ViewStyle } from 'react-native';
2+
import { useEffect, useLayoutEffect, useRef } from 'react';
3+
import { StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native';
44
import ChartManager, { Item, WAVE_DELAY_MS } from './ChartManager';
55
import Animated, {
66
useAnimatedStyle,
77
useSharedValue,
88
withSpring,
99
} from 'react-native-reanimated';
1010

11+
export type Coordinate = {
12+
x: number;
13+
y: number;
14+
};
15+
1116
interface ChartItemProps {
1217
item: Item;
1318
chartManager: ChartManager;
14-
innerRef?: (element: View) => void;
19+
updateCoordinates?: (id: number, coordinate: Coordinate) => void;
1520
style?: StyleProp<ViewStyle>;
1621
}
1722

23+
const getCenter = (side: number, size: number) => side + size / 2;
24+
1825
export default function ChartItem({
1926
item,
2027
chartManager,
21-
innerRef,
28+
updateCoordinates,
2229
style,
2330
}: ChartItemProps) {
31+
const ref = useRef<View>(null);
32+
2433
const progress = useSharedValue(0);
2534

2635
useEffect(() => {
@@ -56,6 +65,21 @@ export default function ChartItem({
5665
};
5766
});
5867

68+
useLayoutEffect(() => {
69+
const box = (
70+
ref.current as unknown as HTMLElement
71+
)?.getBoundingClientRect?.();
72+
73+
if (!box) {
74+
return; // no-op on undefined view ref
75+
}
76+
77+
updateCoordinates(item.id, {
78+
x: getCenter(box.left, box.width),
79+
y: getCenter(box.top, box.height),
80+
});
81+
}, [item, updateCoordinates]);
82+
5983
return (
6084
// @ts-ignore This is legacy code, it works regardless of this error.
6185
<Grid item style={styles.box} xs={3}>
@@ -66,7 +90,7 @@ export default function ChartItem({
6690
animatedStyle,
6791
style,
6892
]}
69-
ref={innerRef}>
93+
ref={ref}>
7094
<Animated.Text style={[animatedTextStyle, styles.label, style]}>
7195
{item.label}
7296
</Animated.Text>

packages/docs-gesture-handler/src/examples/GestureStateFlowExample/FlowChart.tsx

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,33 @@
1-
import { useEffect, useMemo, useRef, useState } from 'react';
1+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
22
import { StyleSheet, View } from 'react-native';
33
import ChartManager from './ChartManager';
44
import { Grid } from '@mui/material';
5-
import ChartItem from './ChartItem';
5+
import ChartItem, { Coordinate } from './ChartItem';
66
import Arrow from './Arrow';
77

8-
type Coordinate = {
9-
x: number;
10-
y: number;
11-
};
12-
138
type FlowChartProps = {
149
chartManager: ChartManager;
1510
};
1611

17-
const getCenter = (side: number, size: number) => side + size / 2;
18-
1912
export default function FlowChart({ chartManager }: FlowChartProps) {
20-
const itemsRef = useRef<View[]>([]);
13+
const coordinates = useMemo<Map<number, Coordinate>>(() => new Map(), []);
14+
2115
const rootRef = useRef<View>(null);
2216

17+
const updateCoordinates = useCallback(
18+
(id: number, coordinate: Coordinate) => {
19+
const htmlRootElement = rootRef.current as unknown as HTMLElement;
20+
const root = htmlRootElement.getBoundingClientRect();
21+
22+
// Adjust to root relative positioning
23+
coordinates.set(id, {
24+
x: coordinate.x - root.left,
25+
y: coordinate.y - root.top,
26+
});
27+
},
28+
[coordinates]
29+
);
30+
2331
// Arrows are not shown on the first render on production builds.
2432
// This `counter` forces a re-render after the component is mounted.
2533
const [counter, setCounter] = useState(0);
@@ -30,31 +38,6 @@ export default function FlowChart({ chartManager }: FlowChartProps) {
3038
return () => clearTimeout(timeout);
3139
}, [counter]);
3240

33-
const itemsCoords = useMemo<Coordinate[]>(
34-
() =>
35-
itemsRef.current.map((element: View | undefined) => {
36-
// During unloading or reresizing, element may reload itself, causing it to be undefined
37-
if (!element) {
38-
return {
39-
x: 0,
40-
y: 0,
41-
} as Coordinate;
42-
}
43-
44-
const htmlElement = element as unknown as HTMLElement;
45-
const htmlRootElement = rootRef.current as unknown as HTMLElement;
46-
47-
const box = htmlElement.getBoundingClientRect();
48-
const root = htmlRootElement.getBoundingClientRect();
49-
50-
return {
51-
x: getCenter(box.left, box.width) - root.left,
52-
y: getCenter(box.top, box.height) - root.top,
53-
} as Coordinate;
54-
}),
55-
[]
56-
);
57-
5841
return (
5942
<View style={styles.container} ref={rootRef}>
6043
<Grid container rowGap={4}>
@@ -65,9 +48,7 @@ export default function FlowChart({ chartManager }: FlowChartProps) {
6548
.map((item) => (
6649
<ChartItem
6750
key={item.id}
68-
innerRef={(el) => {
69-
itemsRef.current[item.id] = el;
70-
}}
51+
updateCoordinates={updateCoordinates}
7152
item={item}
7253
chartManager={chartManager}
7354
/>
@@ -78,19 +59,23 @@ export default function FlowChart({ chartManager }: FlowChartProps) {
7859
{chartManager.connections.map((connection) => {
7960
// we have all the connections layed out,
8061
// but the user may choose not to use some of the available items,
81-
if (!itemsCoords[connection.from] || !itemsCoords[connection.to]) {
62+
if (
63+
!coordinates.get(connection.from) ||
64+
!coordinates.get(connection.to)
65+
) {
8266
return <View key={connection.id} />;
8367
}
68+
8469
return (
8570
<Arrow
8671
key={connection.id}
8772
startPoint={{
88-
x: itemsCoords[connection.from].x,
89-
y: itemsCoords[connection.from].y,
73+
x: coordinates.get(connection.from).x,
74+
y: coordinates.get(connection.from).y,
9075
}}
9176
endPoint={{
92-
x: itemsCoords[connection.to].x,
93-
y: itemsCoords[connection.to].y,
77+
x: coordinates.get(connection.to).x,
78+
y: coordinates.get(connection.to).y,
9479
}}
9580
/>
9681
);

0 commit comments

Comments
 (0)