Skip to content

Commit

Permalink
feat(linechart): add line chart
Browse files Browse the repository at this point in the history
  • Loading branch information
friyiajr committed Jul 15, 2024
1 parent e9554f6 commit c0738e9
Show file tree
Hide file tree
Showing 7 changed files with 606 additions and 21 deletions.
6 changes: 4 additions & 2 deletions example/storybook-nativewind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@react-native-community/slider": "4.2.4",
"@react-stately/collections": "^3.6.0",
"@react-stately/tree": "^3.5.0",
"@shopify/react-native-skia": "^1.3.8",
"expo": "^47.0.0",
"expo-linear-gradient": "^12.3.0",
"expo-status-bar": "~1.4.2",
Expand All @@ -64,7 +65,7 @@
"react-dom": "^18.2.0",
"react-native": "0.72.4",
"react-native-gesture-handler": "~2.14.0",
"react-native-reanimated": "~3.6.2",
"react-native-reanimated": "^3.14.0",
"react-native-safe-area-context": "^4.4.1",
"react-native-svg": "13.4.0",
"react-native-vector-icons": "^10.0.0",
Expand All @@ -74,7 +75,8 @@
"tailwind-variants": "^0.1.20",
"tailwindcss": "^3.4.1",
"ts-jest": "^29.1.0",
"uuidv4": "^6.2.13"
"uuidv4": "^6.2.13",
"victory-native": "^41.0.1"
},
"devDependencies": {
"@babel/core": "^7.19.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ComponentMeta } from '@storybook/react-native';
import LineChart from './LineChart';

const AccordionMeta: ComponentMeta<typeof LineChart> = {
title: 'stories/Line Chart',
component: LineChart,
// metaInfo is required for figma generation
// @ts-ignore
metaInfo: {
componentDescription: `The Line Chart component displays data compatable with a two-dimensional cartesian plane`,
},
argTypes: {},
};

export default AccordionMeta;

export { LineChart };
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState } from 'react';

import { LineChart } from '@/components/ui/line-chart';

import { Button, View, StyleSheet, useColorScheme } from 'react-native';

const DATA = Array.from({ length: 31 }, (_, i) => ({
x: i,
y: 40 + 30 * Math.random(),
}));
const DATA2 = Array.from({ length: 31 }, (_, i) => ({
x: i,
y: 40 + 30 * Math.random(),
}));

const LineChartBasic = () => {
const [data, setData] = useState(DATA);
const colorMode = useColorScheme();

const labelColor = colorMode === 'dark' ? 'white' : 'black';
const lineColor = colorMode === 'dark' ? 'lightgrey' : 'black';

return (
<View style={style.container}>
<LineChart
width={300}
height={300}
data={data}
outlineColor="lightgreen"
gradientColors={['green', '#90ee9050']}
labelColor={labelColor}
lineColor={lineColor}
topLabelPrefix="$"
/>
<Button
title="Change to Data 1"
onPress={() => {
setData(DATA);
}}
/>
<Button
title="Change to Data 2"
onPress={() => {
setData(DATA2);
}}
/>
</View>
);
};

LineChartBasic.description =
'This is a basic Line Chart example. The Line Chart is a component that lets you display data on a two dimensional cartesian plane';

export default LineChartBasic;

const style = StyleSheet.create({
container: {
height: '100%',
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React from 'react';

import {
Circle,
LinearGradient,
matchFont,
vec,
} from '@shopify/react-native-skia';
import { Platform } from 'react-native';
import { useDerivedValue, type SharedValue } from 'react-native-reanimated';
import { Area, CartesianChart, Line, useChartPressState } from 'victory-native';

import { Text as SKText } from '@shopify/react-native-skia';
import { Box } from '@gluestack-ui/themed';

const fontFamily = Platform.select({ ios: 'Helvetica', default: 'sans-serif' });

const legendFontStyle = {
fontFamily,
fontSize: 14,
fontWeight: 'bold',
};

const indicatorFontStyle = {
fontFamily,
fontSize: 25,
fontWeight: 'bold',
};

// @ts-ignore
const legendFont = matchFont(legendFontStyle);
// @ts-ignore
const indicatorFont = matchFont(indicatorFontStyle);

interface ChartData {
[x: string]: number;
}

interface Props {
height: number;
width: number;
data: ChartData[];
outlineColor: string;
gradientColors: string[];
labelColor: string;
lineColor: string;
topLabelPrefix?: string;
topLabelSuffix?: string;
}

export const LineChart = ({
height,
width,
data,
outlineColor,
gradientColors,
labelColor,
lineColor,
topLabelPrefix = '',
topLabelSuffix = '',
}: Props) => {
const { state, isActive } = useChartPressState({ x: 0, y: { y: 0 } });

const value = useDerivedValue(() => {
return topLabelPrefix + state.y.y.value.value.toFixed(2) + topLabelSuffix;
}, [state]);

return (
<Box height={height} width={width}>
<CartesianChart
data={data}
xKey="x"
yKeys={['y']}
domainPadding={{ top: 30 }}
axisOptions={{
font: legendFont,
labelColor,
lineColor,
}}
chartPressState={state}
>
{({ points, chartBounds }) => (
<>
<SKText
x={chartBounds.left + 10}
y={chartBounds.top + indicatorFont.measureText('0').height + 5}
font={indicatorFont}
text={value}
color={labelColor}
style={'fill'}
/>
<Line
points={points.y}
color={outlineColor}
strokeWidth={3}
animate={{ type: 'timing', duration: 500 }}
/>
<Area
points={points.y}
y0={chartBounds.bottom}
animate={{ type: 'timing', duration: 500 }}
>
<LinearGradient
start={vec(chartBounds.bottom, 200)}
end={vec(chartBounds.bottom, chartBounds.bottom)}
colors={gradientColors}
/>
</Area>

{isActive ? (
<ToolTip x={state.x.position} y={state.y.y.position} />
) : null}
</>
)}
</CartesianChart>
</Box>
);
};

function ToolTip({ x, y }: { x: SharedValue<number>; y: SharedValue<number> }) {
return <Circle cx={x} cy={y} r={8} color={'grey'} opacity={0.8} />;
}
6 changes: 4 additions & 2 deletions example/storybook-v7/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@react-native-async-storage/async-storage": "1.23.1",
"@react-native-community/datetimepicker": "8.0.1",
"@react-native-community/slider": "4.5.2",
"@shopify/react-native-skia": "1.2.3",
"autoprefixer": "^10.4.19",
"eas-cli": "^9.0.7",
"expo": "^51.0.8",
Expand All @@ -40,12 +41,13 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.1",
"react-native-gesture-handler": "~2.14.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.1",
"react-native-svg": "15.2.0",
"react-native-web": "~0.19.10",
"tailwind-variants": "^0.2.1"
"tailwind-variants": "^0.2.1",
"victory-native": "^41.0.1"
},
"devDependencies": {
"@babel/core": "^7.19.3",
Expand Down
Loading

0 comments on commit c0738e9

Please sign in to comment.