Skip to content

Commit

Permalink
Feat/scroll (#437)
Browse files Browse the repository at this point in the history
  • Loading branch information
keithluchtel authored Dec 13, 2024
1 parent 1871c0d commit 6b996e2
Show file tree
Hide file tree
Showing 20 changed files with 691 additions and 95 deletions.
5 changes: 5 additions & 0 deletions .changeset/seven-walls-cough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"victory-native": minor
---

Add ability to scroll chart data
210 changes: 210 additions & 0 deletions example/app/scroll.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
export const PanZoom = () => {};
import * as React from "react";
import { StyleSheet, View, SafeAreaView } from "react-native";
import {
CartesianChart,
invert4,
Line,
useChartTransformState,
type ChartBounds,
type Viewport,
} from "victory-native";
import {
mapPoint3d,
Matrix4,
Rect,
scale,
useFont,
} from "@shopify/react-native-skia";
import {
interpolate,
useDerivedValue,
useSharedValue,
type SharedValue,
} from "react-native-reanimated";
import { appColors } from "../consts/colors";
import inter from "../assets/inter-medium.ttf";

export default function HorizontalScrollPage() {
const font = useFont(inter, 12);
const { state } = useChartTransformState({});
const viewport: Viewport = {
x: [5, 15],
y: [50, 60],
};

return (
<SafeAreaView style={styles.safeView}>
<View style={{ flex: 1, maxHeight: 400, padding: 32 }}>
<CartesianChart
data={DATA}
viewport={viewport}
xKey="day"
yKeys={["highTmp"]}
yAxis={[
{
font: font,
},
]}
xAxis={{
font: font,
}}
transformState={state}
transformConfig={{
pan: {
dimensions: ["x", "y"],
},
pinch: {
enabled: false,
},
}}
>
{({ points }) => {
return (
<>
<Line points={points.highTmp} color="red" strokeWidth={3} />
</>
);
}}
</CartesianChart>
</View>
<Hightlighted viewport={viewport} matrix={state.matrix} />
</SafeAreaView>
);
}

type HightlightedProps = {
viewport: Viewport;
matrix: SharedValue<Matrix4>;
};
const Hightlighted = ({ viewport, matrix }: HightlightedProps) => {
const font = useFont(inter, 12);
const [chartBounds, setChartBounds] = React.useState<ChartBounds>({
left: 0,
right: 0,
top: 0,
bottom: 0,
});
const domainX = useSharedValue<[number, number]>([0, 0]);
const domainY = useSharedValue<[number, number]>([0, 0]);
const box = useDerivedValue(() => {
const vp: Required<Viewport> = { ...{ x: [0, 0], y: [0, 0] }, ...viewport };
const kx = (domainX.value[1] - domainX.value[0]) / (vp.x[1] - vp.x[0]) || 1;
const ky = (domainY.value[0] - domainY.value[1]) / (vp.y[1] - vp.y[0]) || 1;

const boundsX = [0, (chartBounds.right - chartBounds.left) * kx];
const boundsY = [0, (chartBounds.bottom - chartBounds.top) * ky];
const x1z = interpolate(vp.x[0], domainX.value, boundsX);
const x2z = interpolate(vp.x[1], domainX.value, boundsX);
const y1z = interpolate(vp.y[0], domainY.value, boundsY);
const y2z = interpolate(vp.y[1], domainY.value, boundsY);

const tl = mapPoint3d(invert4(matrix.value), [x1z, y1z, 1]);
const br = mapPoint3d(invert4(matrix.value), [x2z, y2z, 1]);

const m = scale(kx, ky, 1);
const x1 = mapPoint3d(invert4(m), tl)[0];
const x2 = mapPoint3d(invert4(m), br)[0];
const y1 = mapPoint3d(invert4(m), tl)[1];
const y2 = mapPoint3d(invert4(m), br)[1];

return { x: [x1, x2], y: [y1, y2] };
});
const x = useDerivedValue(() => {
return box.value.x[0]! + chartBounds.left;
});
const w = useDerivedValue(() => {
return box.value.x[1]! - box.value.x[0]!;
});
const y = useDerivedValue(() => {
return box.value.y[0]! + chartBounds.top;
});
const h = useDerivedValue(() => {
return box.value.y[1]! - box.value.y[0]!;
});

return (
<View style={{ flex: 1, maxHeight: 400, padding: 32 }}>
<CartesianChart
data={DATA}
xKey="day"
yKeys={["highTmp"]}
yAxis={[
{
font: font,
},
]}
xAxis={{
font: font,
}}
onChartBoundsChange={(_chartBounds) => {
setChartBounds(() => _chartBounds);
}}
onScaleChange={(_xScale, _yScale) => {
domainX.value = _xScale.domain() as [number, number];
domainY.value = _yScale.domain() as [number, number];
}}
>
{({ points }) => {
return (
<>
<Line points={points.highTmp} color="red" strokeWidth={3} />
<Rect
x={x}
y={y}
width={w}
height={h}
color="green"
opacity={0.3}
/>
</>
);
}}
</CartesianChart>
</View>
);
};

const DATA = [
{ day: 0, highTmp: 59.30624201725173 },
{ day: 1, highTmp: 44.25635578608018 },
{ day: 2, highTmp: 68.19738539273173 },
{ day: 3, highTmp: 47.62255457719107 },
{ day: 4, highTmp: 69.36936311145384 },
{ day: 5, highTmp: 50.341333269749946 },
{ day: 6, highTmp: 54.73478765663331 },
{ day: 7, highTmp: 59.65742044241456 },
{ day: 8, highTmp: 48.221495620289595 },
{ day: 9, highTmp: 58.65209092238778 },
{ day: 10, highTmp: 41.03429979716762 },
{ day: 11, highTmp: 41.10630442396717 },
{ day: 12, highTmp: 45.47205847354351 },
{ day: 13, highTmp: 57.634709409230446 },
{ day: 14, highTmp: 65.87827901279721 },
{ day: 15, highTmp: 47.99811346139486 },
{ day: 16, highTmp: 43.29378262397241 },
{ day: 17, highTmp: 65.0593421561084 },
{ day: 18, highTmp: 56.312569508928775 },
{ day: 19, highTmp: 67.7442403533759 },
{ day: 20, highTmp: 62.84831567105093 },
{ day: 21, highTmp: 53.629213794422405 },
{ day: 22, highTmp: 45.06696838558802 },
{ day: 23, highTmp: 47.95068037187096 },
{ day: 24, highTmp: 45.93743256152696 },
{ day: 25, highTmp: 54.075911101211815 },
{ day: 26, highTmp: 43.777537229307036 },
{ day: 27, highTmp: 49.19553019689158 },
{ day: 28, highTmp: 46.771688955924674 },
{ day: 29, highTmp: 47.74835132388989 },
{ day: 30, highTmp: 40.1617262863485 },
];

const styles = StyleSheet.create({
safeView: {
flex: 1,
backgroundColor: appColors.viewBackground.light,
$dark: {
backgroundColor: appColors.viewBackground.dark,
},
},
});
5 changes: 5 additions & 0 deletions example/consts/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ export const ChartRoutes: {
description: "Basic chart example with a custom tap gesture.",
path: "/custom-gesture",
},
{
title: "Scroll",
description: "Show example of scrolling chart data.",
path: "/scroll",
},
];

if (__DEV__) {
Expand Down
1 change: 1 addition & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@react-native-segmented-control/segmented-control": "2.5.4",
"@shopify/react-native-skia": "1.5.0",
"canvaskit-wasm": "^0.39.1",
"d3-scale": "^4.0.2",
"date-fns": "^2.30.0",
"expo": "^52.0.5",
"expo-asset": "~11.0.1",
Expand Down
Loading

0 comments on commit 6b996e2

Please sign in to comment.