Skip to content

Commit 307d175

Browse files
committed
refactor: create chart page and move screens around
1 parent efee5a4 commit 307d175

File tree

9 files changed

+3158
-111
lines changed

9 files changed

+3158
-111
lines changed

example/app/_layout.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
/* eslint-disable import/no-duplicates */
22
/* eslint-disable prettier/prettier */
33
import "react-native-gesture-handler";
4-
import { Slot } from "expo-router";
4+
import { Stack } from "expo-router";
55
import { StyleSheet } from "react-native";
66
import { GestureHandlerRootView } from "react-native-gesture-handler";
77

88
export default () => (
99
<GestureHandlerRootView style={styles.container}>
10-
<Slot />
10+
<Stack>
11+
<Stack.Screen name="index" />
12+
<Stack.Screen name="chart" />
13+
</Stack>
1114
</GestureHandlerRootView>
1215
);
1316

example/app/chart.tsx

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import {
2+
type AxisLabelComponentProps,
3+
LineChart,
4+
type PanGestureHandlerOnChangeEventPayload,
5+
HoverGestureHandlerOnChangeEventPayload,
6+
} from "@codeherence/react-native-graph";
7+
import { LinearGradient, vec } from "@shopify/react-native-skia";
8+
import { useCallback, useMemo, useReducer } from "react";
9+
import { Button, ScrollView, StyleSheet, Text } from "react-native";
10+
import { useAnimatedProps, useSharedValue } from "react-native-reanimated";
11+
import { useSafeAreaInsets } from "react-native-safe-area-context";
12+
13+
import AnimatedText from "../components/AnimatedText";
14+
import aapl_prices from "../data/aapl_prices.json";
15+
import msft_prices from "../data/msft_prices.json";
16+
import nvda_prices from "../data/nvda_prices.json";
17+
import unity_prices from "../data/unity_prices.json";
18+
19+
const formatter = new Intl.NumberFormat("en-US", {
20+
style: "currency",
21+
currency: "USD",
22+
});
23+
24+
const AxisLabel: React.FC<AxisLabelComponentProps> = ({ value }) => (
25+
<Text selectable={false}>{formatter.format(value)}</Text>
26+
);
27+
28+
const uiFormatter = (price: number) => {
29+
"worklet";
30+
31+
return new Intl.NumberFormat("en-US", {
32+
style: "currency",
33+
currency: "USD",
34+
}).format(price);
35+
};
36+
37+
const priceMap = {
38+
msft: msft_prices.results
39+
.reverse()
40+
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
41+
aapl: aapl_prices.results
42+
.reverse()
43+
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
44+
nvda: nvda_prices.results
45+
.reverse()
46+
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
47+
unity: unity_prices.results
48+
.reverse()
49+
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
50+
};
51+
52+
const priceMapKeys = Object.keys(priceMap) as (keyof typeof priceMap)[];
53+
54+
export default () => {
55+
const [counter, increment] = useReducer((s: number) => s + 1, 0);
56+
57+
const { bottom, left, right } = useSafeAreaInsets();
58+
59+
const latestPrice = useSharedValue("0");
60+
const symbol = priceMapKeys[counter % priceMapKeys.length]!;
61+
const data: [number, number][] = useMemo(() => {
62+
latestPrice.value = uiFormatter(priceMap[symbol][priceMap[symbol].length - 1]![1]);
63+
return priceMap[symbol];
64+
}, [symbol]);
65+
66+
const onHoverChangeWorklet = useCallback((evt: HoverGestureHandlerOnChangeEventPayload) => {
67+
"worklet";
68+
latestPrice.value = uiFormatter(evt.point);
69+
}, []);
70+
71+
const onGestureChangeWorklet = useCallback((evt: PanGestureHandlerOnChangeEventPayload) => {
72+
"worklet";
73+
latestPrice.value = uiFormatter(evt.point);
74+
}, []);
75+
76+
const onEndWorklet = useCallback(() => {
77+
"worklet";
78+
latestPrice.value = uiFormatter(data[data.length - 1]![1]);
79+
}, [data]);
80+
81+
const animatedProps = useAnimatedProps(() => {
82+
return { text: latestPrice.value };
83+
}, []);
84+
85+
return (
86+
<ScrollView
87+
style={styles.container}
88+
contentContainerStyle={{
89+
paddingBottom: bottom,
90+
paddingLeft: left,
91+
paddingRight: right,
92+
}}
93+
showsVerticalScrollIndicator={false}
94+
>
95+
<Button title={`Showing ${symbol}. Click to switch.`} onPress={increment} />
96+
<AnimatedText style={styles.price} animatedProps={animatedProps} />
97+
<LineChart
98+
points={data}
99+
style={styles.chart}
100+
TopAxisLabel={AxisLabel}
101+
BottomAxisLabel={AxisLabel}
102+
onPanGestureChange={onGestureChangeWorklet}
103+
onPanGestureEnd={onEndWorklet}
104+
onHoverGestureEnd={onEndWorklet}
105+
onHoverGestureChange={onHoverChangeWorklet}
106+
strokeWidth={2}
107+
PathFill={({ width }) => (
108+
<LinearGradient
109+
start={vec(0, 0)}
110+
end={vec(width, 0)}
111+
colors={["blue", "red", "purple"]}
112+
/>
113+
)}
114+
/>
115+
</ScrollView>
116+
);
117+
};
118+
119+
const styles = StyleSheet.create({
120+
container: { flex: 1 },
121+
chart: { flex: 1, minHeight: 400 },
122+
price: { fontSize: 32 },
123+
});

example/app/index.tsx

Lines changed: 16 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,31 @@
1-
import {
2-
type AxisLabelComponentProps,
3-
LineChart,
4-
type PanGestureHandlerOnChangeEventPayload,
5-
HoverGestureHandlerOnChangeEventPayload,
6-
} from "@codeherence/react-native-graph";
7-
import { LinearGradient, vec } from "@shopify/react-native-skia";
8-
import { useCallback, useMemo, useReducer } from "react";
9-
import { Button, ScrollView, StyleSheet, Text, View } from "react-native";
10-
import { useAnimatedProps, useSharedValue } from "react-native-reanimated";
11-
import { useSafeAreaInsets } from "react-native-safe-area-context";
12-
13-
import AnimatedText from "../components/AnimatedText";
14-
import aapl_prices from "../data/aapl_prices.json";
15-
import msft_prices from "../data/msft_prices.json";
16-
17-
const formatter = new Intl.NumberFormat("en-US", {
18-
style: "currency",
19-
currency: "USD",
20-
});
21-
22-
const AxisLabel: React.FC<AxisLabelComponentProps> = ({ value }) => (
23-
<Text selectable={false}>{formatter.format(value)}</Text>
24-
);
25-
26-
const uiFormatter = (price: number) => {
27-
"worklet";
28-
29-
return new Intl.NumberFormat("en-US", {
30-
style: "currency",
31-
currency: "USD",
32-
}).format(price);
33-
};
34-
35-
const priceMap = {
36-
msft: msft_prices.results
37-
.reverse()
38-
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
39-
aapl: aapl_prices.results
40-
.reverse()
41-
.map<[number, number]>((r) => [new Date(r.date).getTime(), r.close]),
42-
};
1+
import { useRouter } from "expo-router";
2+
import { Pressable, ScrollView, StyleSheet, Text } from "react-native";
433

444
export default () => {
45-
const [counter, increment] = useReducer((s: number) => s + 1, 0);
46-
47-
const { top, bottom, left, right } = useSafeAreaInsets();
48-
49-
const latestPrice = useSharedValue("0");
50-
const symbol: "msft" | "aapl" = counter % 2 === 0 ? "msft" : "aapl";
51-
const data: [number, number][] = useMemo(() => {
52-
latestPrice.value = uiFormatter(priceMap[symbol][priceMap[symbol].length - 1]![1]);
53-
return priceMap[symbol];
54-
}, [symbol]);
55-
56-
const onHoverChangeWorklet = useCallback((evt: HoverGestureHandlerOnChangeEventPayload) => {
57-
"worklet";
58-
latestPrice.value = uiFormatter(evt.point);
59-
}, []);
60-
61-
const onGestureChangeWorklet = useCallback((evt: PanGestureHandlerOnChangeEventPayload) => {
62-
"worklet";
63-
latestPrice.value = uiFormatter(evt.point);
64-
}, []);
65-
66-
const onEndWorklet = useCallback(() => {
67-
"worklet";
68-
latestPrice.value = uiFormatter(data[data.length - 1]![1]);
69-
}, [data]);
70-
71-
const animatedProps = useAnimatedProps(() => {
72-
return { text: latestPrice.value };
73-
}, []);
5+
const { push } = useRouter();
746

757
return (
768
<ScrollView
779
style={styles.container}
78-
contentContainerStyle={{
79-
paddingTop: top,
80-
paddingBottom: bottom,
81-
paddingLeft: left,
82-
paddingRight: right,
83-
}}
10+
contentContainerStyle={styles.contentContainer}
8411
showsVerticalScrollIndicator={false}
8512
>
86-
<Button title={`Showing ${symbol}. Click to switch.`} onPress={increment} />
87-
<AnimatedText style={styles.price} animatedProps={animatedProps} />
88-
<LineChart
89-
points={data}
90-
style={styles.chart}
91-
TopAxisLabel={AxisLabel}
92-
BottomAxisLabel={AxisLabel}
93-
onPanGestureChange={onGestureChangeWorklet}
94-
onPanGestureEnd={onEndWorklet}
95-
onHoverGestureEnd={onEndWorklet}
96-
onHoverGestureChange={onHoverChangeWorklet}
97-
strokeWidth={2}
98-
PathFill={({ width }) => (
99-
<LinearGradient
100-
start={vec(0, 0)}
101-
end={vec(width, 0)}
102-
colors={["blue", "red", "purple"]}
103-
/>
104-
)}
105-
/>
13+
<Pressable onPress={() => push("/chart")}>
14+
<Text style={styles.link}>Go to Charts</Text>
15+
</Pressable>
10616
</ScrollView>
10717
);
10818
};
10919

11020
const styles = StyleSheet.create({
11121
container: { flex: 1 },
112-
chart: { flex: 1, minHeight: 400 },
113-
price: { fontSize: 32 },
22+
contentContainer: {
23+
flexGrow: 1,
24+
},
25+
link: {
26+
color: "blue",
27+
fontSize: 16,
28+
textAlign: "center",
29+
padding: 16,
30+
},
11431
});

0 commit comments

Comments
 (0)