Use new chart library in ViewGraph

This commit is contained in:
Brandon Presley 2023-10-26 12:20:15 +13:00
parent f28406b4c4
commit 1c10e0f632
2 changed files with 78 additions and 93 deletions

108
Chart.tsx
View File

@ -1,69 +1,55 @@
import { useTheme } from "@react-navigation/native";
import * as shape from "d3-shape";
import { View } from "react-native";
import { Grid, LineChart, XAxis, YAxis } from "react-native-svg-charts";
import { CombinedDarkTheme, CombinedDefaultTheme } from "./App";
import { MARGIN, PADDING } from "./constants";
import { useMemo } from "react";
import { useWindowDimensions } from "react-native";
import { LineChart } from "react-native-chart-kit";
import { AbstractChartConfig } from "react-native-chart-kit/dist/AbstractChart";
import { PADDING } from "./constants";
import useDark from "./use-dark";
import { useTheme } from "react-native-paper";
export default function Chart({
yData,
xFormat,
xData,
yFormat,
}: {
yData: number[];
xData: unknown[];
xFormat: (value: any, index: number) => string;
yFormat: (value: any) => string;
}) {
interface ChartProps {
labels: string[];
data: number[];
preserve?: number;
}
export default function Chart({ labels, data, preserve = 3 }: ChartProps) {
const { width } = useWindowDimensions();
const { colors } = useTheme();
const dark = useDark();
const axesSvg = {
fontSize: 10,
fill: dark
? CombinedDarkTheme.colors.text
: CombinedDefaultTheme.colors.text,
const config: AbstractChartConfig = {
backgroundGradientFrom: colors.background,
backgroundGradientTo: colors.elevation.level1,
color: () => colors.primary,
};
const verticalContentInset = { top: 10, bottom: 10 };
const xAxisHeight = 30;
const pruned = useMemo(() => {
const newPruned = [...labels];
if (labels.length <= preserve + 2) return labels;
let interval = Math.floor((labels.length - 2) / (preserve + 1));
for (let i = 1; i < labels.length - 1; i++) {
if ((i - 1) % interval !== 0 || i === 1) {
newPruned[i] = "";
}
}
return newPruned;
}, [labels, preserve]);
console.log({ labels, data, pruned, preserve });
return (
<>
<View
style={{
height: 300,
padding: PADDING,
flexDirection: "row",
}}
>
<YAxis
data={yData}
style={{ marginBottom: xAxisHeight }}
contentInset={verticalContentInset}
svg={axesSvg}
formatLabel={yFormat}
/>
<View style={{ flex: 1, marginLeft: MARGIN }}>
<LineChart
style={{ flex: 1 }}
data={yData}
contentInset={verticalContentInset}
curve={shape.curveBasis}
svg={{
stroke: colors.primary,
}}
>
<Grid />
</LineChart>
<XAxis
data={xData}
formatLabel={xFormat}
contentInset={{ left: 15, right: 16 }}
svg={axesSvg}
/>
</View>
</View>
</>
<LineChart
height={400}
width={width - 20}
data={{
labels: pruned,
datasets: [
{
data,
},
],
}}
chartConfig={config}
/>
);
}

View File

@ -1,5 +1,4 @@
import { RouteProp, useRoute } from "@react-navigation/native";
import { format } from "date-fns";
import { useEffect, useMemo, useState } from "react";
import { View } from "react-native";
import { FileSystem } from "react-native-file-access";
@ -16,6 +15,7 @@ import GymSet from "./gym-set";
import { Metrics } from "./metrics";
import { Periods } from "./periods";
import Volume from "./volume";
import { format } from "date-fns";
export default function ViewGraph() {
const { params } = useRoute<RouteProp<GraphsPageParams, "ViewGraph">>();
@ -70,41 +70,38 @@ export default function ViewGraph() {
}, [params.name, metric, period]);
const charts = useMemo(() => {
if (
(metric === Metrics.Volume && volumes?.length === 0) ||
(metric === Metrics.Best && weights?.length === 0) ||
(metric === Metrics.OneRepMax && weights?.length === 0)
) {
return <List.Item title="No data yet." />;
}
if (metric === Metrics.Volume && volumes?.length && weights?.length) {
let periodFormat = "do";
if (period === Periods.Weekly) periodFormat = "iii";
else if (period === Periods.Yearly) periodFormat = "P";
let preserve = 3;
if (period === Periods.Yearly) preserve = 1;
if (metric === Metrics.Volume && Number(volumes?.length) > 0)
return (
<Chart
yData={volumes.map((v) => v.value)}
yFormat={(value: number) =>
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}${
volumes[0].unit || "kg"
}`
}
xData={weights}
xFormat={(_value, index) =>
format(new Date(weights[index].created), "d/M")
}
data={volumes.map((volume) => volume.value)}
labels={volumes.map((volume) =>
format(new Date(volume.created), periodFormat)
)}
preserve={preserve}
/>
);
if (
(metric === Metrics.Best || metric === Metrics.OneRepMax) &&
Number(weights?.length) > 0
)
return (
<Chart
data={weights.map((set) => set.weight)}
labels={weights.map((set) =>
format(new Date(set.created), periodFormat)
)}
preserve={preserve}
/>
);
}
return (
<Chart
yData={weights?.map((set) => set.weight) || []}
yFormat={(value) => `${value}${weights?.[0].unit}`}
xData={weights || []}
xFormat={(_value, index) =>
format(new Date(weights?.[index].created), "d/M")
}
/>
);
}, [volumes, weights, metric]);
return <List.Item title="No data yet." />;
}, [volumes, weights, metric, period]);
return (
<>
@ -144,7 +141,9 @@ export default function ViewGraph() {
onChange={(value) => setPeriod(value as Periods)}
value={period}
/>
{charts}
<View style={{ paddingTop: PADDING }}>
{(weights || volumes) && charts}
</View>
</View>
</>
);