Use new chart library in ViewGraph
This commit is contained in:
parent
f28406b4c4
commit
1c10e0f632
108
Chart.tsx
108
Chart.tsx
|
@ -1,69 +1,55 @@
|
||||||
import { useTheme } from "@react-navigation/native";
|
import { useMemo } from "react";
|
||||||
import * as shape from "d3-shape";
|
import { useWindowDimensions } from "react-native";
|
||||||
import { View } from "react-native";
|
import { LineChart } from "react-native-chart-kit";
|
||||||
import { Grid, LineChart, XAxis, YAxis } from "react-native-svg-charts";
|
import { AbstractChartConfig } from "react-native-chart-kit/dist/AbstractChart";
|
||||||
import { CombinedDarkTheme, CombinedDefaultTheme } from "./App";
|
import { PADDING } from "./constants";
|
||||||
import { MARGIN, PADDING } from "./constants";
|
|
||||||
import useDark from "./use-dark";
|
import useDark from "./use-dark";
|
||||||
|
import { useTheme } from "react-native-paper";
|
||||||
|
|
||||||
export default function Chart({
|
interface ChartProps {
|
||||||
yData,
|
labels: string[];
|
||||||
xFormat,
|
data: number[];
|
||||||
xData,
|
preserve?: number;
|
||||||
yFormat,
|
}
|
||||||
}: {
|
|
||||||
yData: number[];
|
export default function Chart({ labels, data, preserve = 3 }: ChartProps) {
|
||||||
xData: unknown[];
|
const { width } = useWindowDimensions();
|
||||||
xFormat: (value: any, index: number) => string;
|
|
||||||
yFormat: (value: any) => string;
|
|
||||||
}) {
|
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const dark = useDark();
|
|
||||||
const axesSvg = {
|
const config: AbstractChartConfig = {
|
||||||
fontSize: 10,
|
backgroundGradientFrom: colors.background,
|
||||||
fill: dark
|
backgroundGradientTo: colors.elevation.level1,
|
||||||
? CombinedDarkTheme.colors.text
|
color: () => colors.primary,
|
||||||
: CombinedDefaultTheme.colors.text,
|
|
||||||
};
|
};
|
||||||
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 (
|
return (
|
||||||
<>
|
<LineChart
|
||||||
<View
|
height={400}
|
||||||
style={{
|
width={width - 20}
|
||||||
height: 300,
|
data={{
|
||||||
padding: PADDING,
|
labels: pruned,
|
||||||
flexDirection: "row",
|
datasets: [
|
||||||
}}
|
{
|
||||||
>
|
data,
|
||||||
<YAxis
|
},
|
||||||
data={yData}
|
],
|
||||||
style={{ marginBottom: xAxisHeight }}
|
}}
|
||||||
contentInset={verticalContentInset}
|
chartConfig={config}
|
||||||
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>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { RouteProp, useRoute } from "@react-navigation/native";
|
import { RouteProp, useRoute } from "@react-navigation/native";
|
||||||
import { format } from "date-fns";
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { FileSystem } from "react-native-file-access";
|
import { FileSystem } from "react-native-file-access";
|
||||||
|
@ -16,6 +15,7 @@ import GymSet from "./gym-set";
|
||||||
import { Metrics } from "./metrics";
|
import { Metrics } from "./metrics";
|
||||||
import { Periods } from "./periods";
|
import { Periods } from "./periods";
|
||||||
import Volume from "./volume";
|
import Volume from "./volume";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
|
||||||
export default function ViewGraph() {
|
export default function ViewGraph() {
|
||||||
const { params } = useRoute<RouteProp<GraphsPageParams, "ViewGraph">>();
|
const { params } = useRoute<RouteProp<GraphsPageParams, "ViewGraph">>();
|
||||||
|
@ -70,41 +70,38 @@ export default function ViewGraph() {
|
||||||
}, [params.name, metric, period]);
|
}, [params.name, metric, period]);
|
||||||
|
|
||||||
const charts = useMemo(() => {
|
const charts = useMemo(() => {
|
||||||
if (
|
let periodFormat = "do";
|
||||||
(metric === Metrics.Volume && volumes?.length === 0) ||
|
if (period === Periods.Weekly) periodFormat = "iii";
|
||||||
(metric === Metrics.Best && weights?.length === 0) ||
|
else if (period === Periods.Yearly) periodFormat = "P";
|
||||||
(metric === Metrics.OneRepMax && weights?.length === 0)
|
let preserve = 3;
|
||||||
) {
|
if (period === Periods.Yearly) preserve = 1;
|
||||||
return <List.Item title="No data yet." />;
|
|
||||||
}
|
if (metric === Metrics.Volume && Number(volumes?.length) > 0)
|
||||||
if (metric === Metrics.Volume && volumes?.length && weights?.length) {
|
|
||||||
return (
|
return (
|
||||||
<Chart
|
<Chart
|
||||||
yData={volumes.map((v) => v.value)}
|
data={volumes.map((volume) => volume.value)}
|
||||||
yFormat={(value: number) =>
|
labels={volumes.map((volume) =>
|
||||||
`${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}${
|
format(new Date(volume.created), periodFormat)
|
||||||
volumes[0].unit || "kg"
|
)}
|
||||||
}`
|
preserve={preserve}
|
||||||
}
|
/>
|
||||||
xData={weights}
|
);
|
||||||
xFormat={(_value, index) =>
|
if (
|
||||||
format(new Date(weights[index].created), "d/M")
|
(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 (
|
return <List.Item title="No data yet." />;
|
||||||
<Chart
|
}, [volumes, weights, metric, period]);
|
||||||
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -144,7 +141,9 @@ export default function ViewGraph() {
|
||||||
onChange={(value) => setPeriod(value as Periods)}
|
onChange={(value) => setPeriod(value as Periods)}
|
||||||
value={period}
|
value={period}
|
||||||
/>
|
/>
|
||||||
{charts}
|
<View style={{ paddingTop: PADDING }}>
|
||||||
|
{(weights || volumes) && charts}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user