add charts folder in component

This commit is contained in:
Loewy
2024-01-11 22:59:15 -08:00
parent 28a0426096
commit a9afd7e0a9
5 changed files with 1 additions and 1 deletions

48
component/charts/bar.tsx Normal file
View File

@@ -0,0 +1,48 @@
import React from 'react';
import { Path } from 'react-native-svg';
import { calculateBarOrigin, drawBarPath } from './custom-bar-utils';
import { ScaleFunction } from './graph-types';
interface BarProps {
scaleX: ScaleFunction;
scaleY: ScaleFunction;
data: { value: number };
barNumber: number;
index: number;
fill: string;
barWidth: number;
gap: number;
roundedRadius: number;
}
export const Bar: React.FC<BarProps> = ({
scaleX,
scaleY,
data,
barNumber,
index,
fill,
barWidth,
gap,
roundedRadius
}) => {
const { xOrigin, yOrigin, height } = calculateBarOrigin({
scaleX,
scaleY,
index,
data,
barNumber,
barWidth,
gap
});
return (
<Path
key={`bar-path-${barNumber}-${index}`}
d={drawBarPath(xOrigin, yOrigin, barWidth, height, roundedRadius)}
fill={fill}
testID={`bar-${barNumber}-${index}`}
/>
);
};

View File

@@ -0,0 +1,59 @@
import { path as d3 } from 'd3-path';
import { ScaleFunction } from './graph-types';
type BarCalculationProps = {
scaleX: ScaleFunction;
scaleY: ScaleFunction;
data: { value: number };
barNumber: number;
index: number;
barWidth: number;
gap: number;
};
export function calculateBarOrigin({
scaleX,
scaleY,
barWidth,
data,
index,
barNumber,
gap
}: BarCalculationProps): { xOrigin: number; yOrigin: number; height: number } {
const firstBar = barNumber === 0;
const xOrigin = scaleX(index) + (firstBar ? 0 : barWidth * barNumber + gap * barNumber);
const yOrigin = scaleY(data.value);
const height = scaleY(0) - yOrigin;
return { xOrigin, yOrigin, height };
}
export function drawBarPath(
xOrigin: number,
yOrigin: number,
barWidth: number,
height: number,
roundedRadius: number
): string {
const path = d3();
path.moveTo(xOrigin, yOrigin + height);
path.lineTo(xOrigin, yOrigin + roundedRadius);
path.arcTo(xOrigin, yOrigin, xOrigin + roundedRadius, yOrigin, roundedRadius);
path.lineTo(xOrigin + barWidth - roundedRadius, yOrigin);
path.arcTo(
xOrigin + barWidth,
yOrigin,
xOrigin + barWidth,
yOrigin + roundedRadius,
roundedRadius
);
path.lineTo(xOrigin + barWidth, yOrigin + height);
path.lineTo(xOrigin, yOrigin + height);
path.closePath();
return path.toString();
}
export const calculateBarWidth = (bandwidth: number, combinedDataLength: number, gap: number) =>
(bandwidth - gap * (combinedDataLength - 1)) / combinedDataLength;

View File

@@ -0,0 +1,54 @@
import { Svg } from 'react-native-svg';
import { Bar } from './bar';
import { ScaleFunction } from './graph-types';
import { calculateBarWidth } from './custom-bar-utils';
export interface CombinedData {
data: { value: number }[];
svg: { fill: string };
}
interface CustomBarsProps {
x: ScaleFunction;
y: ScaleFunction;
bandwidth: number;
barColors: string[];
rawData: unknown[]; // TODO: update this value when this data type is defined
combinedData: CombinedData[];
gap: number;
roundedRadius: number;
}
export const CustomBars: React.FC<CustomBarsProps> = ({
x: scaleX,
y: scaleY,
bandwidth,
combinedData,
rawData,
barColors,
gap = 2,
roundedRadius = 4
}) => {
const barWidth = calculateBarWidth(bandwidth, combinedData.length, gap);
return rawData.map((_, index) => (
<Svg key={`group-${index}`} testID={`svg-${index}`}>
{combinedData.map((item, i) => (
<Bar
key={`bar-${i}-${index}`}
scaleX={scaleX}
scaleY={scaleY}
data={item.data[index]}
barNumber={i} // index of bar
index={index} // index of group
fill={barColors[i]}
barWidth={barWidth}
gap={gap}
roundedRadius={roundedRadius}
/>
))}
</Svg>
));
};

View File

@@ -0,0 +1,38 @@
import React from 'react';
import { G, Line } from 'react-native-svg';
import { colors } from '../../styles';
import { ScaleFunction } from './graph-types';
interface CustomGridProps {
y: ScaleFunction;
ticks: Array<number>;
}
export const CustomGrid: React.FC<CustomGridProps> = ({ y, ticks }) => {
const [firstTick, ...remainingTicks] = ticks;
const dashArray = [1, 3];
const strokeSolidWidth = 0.2;
const strokeSolidColor = colors.bgBlack;
const strokeDashWidth = 1;
const strokeDashColor = colors.lightGrey;
const renderLine = (tick: number, stroke: string, strokeWidth: number, dashArray?: number[]) => (
<Line
key={`line-${tick}`}
x1="0%"
x2="100%"
y1={y(tick)}
y2={y(tick)}
stroke={stroke}
strokeWidth={strokeWidth}
strokeDasharray={dashArray}
/>
);
return (
<G>
{renderLine(firstTick, strokeSolidColor, strokeSolidWidth)}
{remainingTicks.map((tick) => renderLine(tick, strokeDashColor, strokeDashWidth, dashArray))}
</G>
);
};

View File

@@ -0,0 +1,3 @@
import { ScaleLinear } from 'd3-scale'
export type ScaleFunction = ScaleLinear<number, number>;