add func logic for bar graph

This commit is contained in:
Loewy
2024-01-12 13:04:45 -08:00
parent 4c1bd21f3d
commit 12c3a6ef6f
6 changed files with 205 additions and 2 deletions

View File

@@ -0,0 +1,10 @@
// if values in chartDefaults should not be accessible as props & are a style, move to graphStyles
export const chartDefaults = {
height: 300,
spacingInner: 0.3,
spacingOuter: 0.2,
contentInset: { top: 30, bottom: 30 },
numberOfTicks: 6,
min: 0,
barColors: ['#598EBB', '#F2D4BC', '#DB7878']
};

View File

@@ -1,3 +1,42 @@
import { ScaleLinear } from 'd3-scale'
export type ScaleFunction = ScaleLinear<number, number>;
export type ScaleFunction = ScaleLinear<number, number>;
export interface YAxisData {
key: string; // string value for ChartLabel component
values: number[];
// including this code only for review --
// do we prefer the idea of passing label formatting from the data or in the component?
// generic function type, specific usage of value varies
// eslint-disable-next-line no-unused-vars
formatLabel?: (value: number) => string;
}
export interface GraphData {
xValues: string[];
yValues: YAxisData[];
}
interface YAxisProps {
maxLeftYAxisValue?: number;
maxRightYAxisValue?: number;
selectedLeftYAxisLabel?: string;
selectedRightYAxisLabel?: string;
// generic function type, specific usage of value varies
// eslint-disable-next-line no-unused-vars
formatRightYAxisLabel?: (value: string) => string;
// generic function type, specific usage of value varies
// eslint-disable-next-line no-unused-vars
formatLeftYAxisLabel?: (value: string) => string;
}
export interface Props {
data: GraphData;
height?: number;
spacingInner?: number;
spacingOuter?: number;
contentInset?: { top: number; bottom: number };
min?: number;
numberOfTicks?: number;
barColors?: Array<string>;
yAxisProps?: YAxisProps;
}

View File

@@ -0,0 +1,40 @@
import { GraphData } from "./graph-types";
export const convertToBarData = (
graphData: GraphData,
options: {
selectedLeftYAxisLabel?: string;
selectedRightYAxisLabel?: string;
maxRightYAxisValue: number;
maxLeftYAxisValue: number;
}
) => {
const xValues = graphData.xValues;
const leftAxisIndex = graphData.yValues.findIndex(
(y) => y.key === options.selectedLeftYAxisLabel
);
const rightAxisIndex = graphData.yValues.findIndex(
(y) => y.key === options.selectedRightYAxisLabel
);
// scale data points according to max value
const barData = graphData.yValues.map((yAxis, index) => {
const maxValue =
index === rightAxisIndex ? options.maxRightYAxisValue : options.maxLeftYAxisValue;
// scale values as a percentage of the max value
const scaledValues = yAxis.values.map((value) => (value / maxValue) * 100);
const mappedData = scaledValues.map((scaledValue) => ({ value: scaledValue }));
return {
data: mappedData,
svg: { fill: 'transparent' } // fill handled in CustomBars
};
});
const yAxisLeftLabels = leftAxisIndex !== -1 ? graphData.yValues[leftAxisIndex] : null;
const yAxisRightLabels = rightAxisIndex !== -1 ? graphData.yValues[rightAxisIndex] : undefined;
return { barData, yAxisLeftLabels, yAxisRightLabels, xValues };
};

View File

@@ -0,0 +1,57 @@
import { useMemo } from 'react';
import { convertToBarData } from './graph-utils';
import { chartDefaults } from './graph-config';
import { GraphData, Props, YAxisData } from './graph-types';
interface useGraphDataInterface {
xValues: Array<string>;
barData: {
data: {
value: number;
}[];
svg: {
fill: string;
};
}[];
yAxisLeftLabels: YAxisData;
yAxisRightLabels: YAxisData;
defaultProps: Partial<Props>;
}
// this version assumes string values for X, this isn't necessarily the case
// convertToBarData is specifically tailored to bar/group bar graphs
// ultimately this component could be used by any x & y axis graph types (line/bar/scatter)
export const useGraphData = (graphData: GraphData, props: Partial<Props>): useGraphDataInterface => {
const { yAxisProps = {}, ...otherProps } = props;
const defaultProps = {
...chartDefaults,
...otherProps,
// assign default values for yAxisProps + spread to override with values coming from props
yAxisProps: {
maxLeftYAxisValue: Math.max(...(graphData.yValues[0]?.values ?? [0])),
maxRightYAxisValue:
graphData.yValues.length > 1 ? Math.max(...graphData.yValues[1]?.values) : undefined,
formatRightYAxisLabel: yAxisProps.formatRightYAxisLabel,
formatLeftYAxisLabel: yAxisProps.formatLeftYAxisLabel,
selectedLeftYAxisLabel: graphData.yValues[0]?.key,
selectedRightYAxisLabel: graphData.yValues[1]?.key,
...yAxisProps
}
};
const { barData, yAxisLeftLabels, yAxisRightLabels, xValues } = useMemo(
() => convertToBarData(graphData, defaultProps.yAxisProps),
[graphData, defaultProps.yAxisProps]
);
return {
xValues,
barData,
yAxisLeftLabels,
yAxisRightLabels,
defaultProps
};
};