cl-react-graph
Version:
124 lines (110 loc) • 3.29 kB
text/typescript
import { extent } from 'd3-array';
import {
area,
curveCatmullRom,
CurveFactory,
CurveFactoryLineOnly,
line,
} from 'd3-shape';
import {
useEffect,
useState,
} from 'react';
import { IAxes } from '../legacy/types';
import {
IChartPoint,
IChartPointValue,
ILineProps,
} from '../LineChart';
import { rangeAffordance } from './domain';
import {
AnyScale,
buildScales,
} from './scales';
const ZERO_SUBSTITUTE: number = 1e-6;
export interface IProps<T extends IChartPoint<IChartPointValue, IChartPointValue> = IChartPoint> {
data: T[];
axis: IAxes;
line: ILineProps;
curveType?: CurveFactory | CurveFactoryLineOnly;
width: number;
left?: number;
height: number;
}
export const useScales: (props: Omit<IProps, 'line' | 'curveType'>) => { xScale: any, yScale: any } = ({
data,
width,
height,
axis,
left = 0,
}) => {
const [scales, setScales] = useState<{ xScale: any, yScale: any }>({ xScale: null, yScale: null });
useEffect(() => {
const [xScale, yScale] = buildScales(axis);
const ys: any[] = [];
const xs: any[] = [];
data.forEach((d) => {
let parsedY = axis.y.scale === 'log' && d.y === 0 ? ZERO_SUBSTITUTE : d.y;
let parsedX = axis.x.scale === 'log' && d.x === 0 ? ZERO_SUBSTITUTE : d.x;
ys.push(parsedY);
xs.push(parsedX);
});
const yDomain = rangeAffordance(extent(ys), axis.y);
const xDomain = rangeAffordance(extent(xs), axis.x);
(xScale as any)
.domain(xDomain)
.rangeRound([left, width + left]);
(yScale as any).domain(yDomain)
.range([height, 0]);
setScales({ xScale, yScale })
}, [data, width, height, left])
return scales;
}
export const useMakeLine: (props: IProps) => { previous: string, current: string } = (props) => {
const [current, setCurrent] = useState('');
const [previous, setPrevious] = useState('');
const { xScale, yScale } = useScales(props);
useEffect(() => {
const { data } = props;
const { curveType = curveCatmullRom } = props.line;
if (yScale !== null) {
const curve = (
x: AnyScale,
y: AnyScale,
) => line()
.curve(curveType)
.x((d: any) => {
return x(d.x);
})
.y((d: any) => y(d.y));
const next = String(curve(xScale, yScale)(data as any));
if (next !== current) {
setPrevious(current);
setCurrent(next);
}
}
}, [xScale, yScale, props.data, props.width, props.line])
return { previous, current };
}
export const useMakeArea: (props: IProps) => { previous: string, current: string } = (props) => {
const [current, setCurrent] = useState('');
const [previous, setPrevious] = useState('');
const { xScale, yScale } = useScales(props);
useEffect(() => {
const { data, height } = props;
const { curveType = curveCatmullRom } = props.line;
if (yScale !== null) {
const thisArea = () => area()
.curve(curveType as CurveFactory)
.x((d: any) => xScale(d.x))
.y0((d) => height)
.y1((d: any) => yScale(d.y));
const next = String(thisArea()(data as any));
if (next !== current) {
setPrevious(current);
setCurrent(next);
}
}
}, [xScale, yScale, props.data]);
return { previous, current };
}