UNPKG

cl-react-graph

Version:
192 lines (178 loc) 4.36 kB
import { ScaleLinear } from "d3-scale"; import { SpringConfig } from "@react-spring/web"; import { EChartDirection } from "../../BarChart"; import { BarChartDataSet } from "../../Histogram"; import { ColorScheme, getFill } from "../../utils/colorScheme"; import { ExtendedGroupItem } from "./Bars"; type HistogramSpringProps = { bins: [number, number][]; values: BarChartDataSet[]; height: number; width: number; dataSets: ExtendedGroupItem[]; numericScale: ScaleLinear<any, any>; continuousScale: ScaleLinear<any, any>; colorScheme: ColorScheme; hoverColorScheme?: ColorScheme; config: SpringConfig; direction: EChartDirection; radius?: number; }; /** * Build the from / to spring animation properties to animate the bars. */ export const buildHistogramSprings = (props: HistogramSpringProps) => { const { bins, direction, config, height, dataSets, numericScale, continuousScale, colorScheme, hoverColorScheme, radius = 4, } = props; const s = dataSets.map((item, index) => { const bandPosition = continuousScale(bins[index][0]); // Ensure that if we have bins that don't start at 0 our bars will still have the correct width const startValue = bins[0][0]; const binWidth = bins[index][1] - bins[index][0]; const itemWidth = continuousScale(binWidth + startValue); const itemHeight = numericScale(item.value); const fill = getFill(colorScheme[item.datasetIndex]); const hoverFill = getFill( hoverColorScheme?.[item.datasetIndex] ?? colorScheme[item.datasetIndex] ); if (direction === EChartDirection.HORIZONTAL) { return horizontalSpring({ fill, hoverFill, bandPosition, height, itemWidth, config, itemHeight, radius, }); } return verticalSpring({ fill, hoverFill, bandPosition, height, itemWidth, config, itemHeight, radius, }); }); return s; }; type FnProps = { fill: string; hoverFill: string; bandPosition: number; height: number; itemWidth: number; itemHeight: number; config: SpringConfig; radius: number; }; const horizontalSpring = ({ fill, hoverFill, bandPosition, height, itemWidth, itemHeight, config, radius, }: FnProps) => { const from = { x: 0, y: height - itemWidth - bandPosition, }; const to = { x: 0, y: height - itemWidth - bandPosition, }; let r = radius * 2 < itemHeight ? radius : itemHeight / 2; const topRightCurve = `a${r} ${r} 0 0 1 ${r} ${r}`; const bottomRightCurve = `a${r} ${r} 0 0 1 -${r} ${r}`; const vertical = itemWidth; const horizontal = itemHeight; return { from: { width: 0, d: `m${from.x} ${from.y} h${0} ${topRightCurve} v${ vertical - 2 * r } ${bottomRightCurve} h-${0} v-${vertical - 2 * r}`, fill, hoverFill, x: 0, y: height - itemWidth - bandPosition, height: itemWidth, }, to: { d: `m${to.x} ${to.y} h${horizontal - r} ${topRightCurve} v${ vertical - 2 * r } ${bottomRightCurve} h-${horizontal - r} v-${vertical - 2 * r}`, width: itemHeight, fill, hoverFill, x: 0, y: height - itemWidth - bandPosition, height: itemWidth, }, config, }; }; const verticalSpring = ({ fill, hoverFill, bandPosition, height, itemWidth, itemHeight, config, radius, }: FnProps) => { const r = radius * 2 < itemWidth ? radius : itemWidth / 2; const topLeftCurve = `a${r},${r} 0 0 1 ${r},-${r}`; const topRightCurve = `a${r} ${r} 0 0 1 ${r} ${r}`; const from = { x: bandPosition, y: height, }; const to = { x: bandPosition, y: height, }; return { from: { height: 0, d: `m${from.x} ${from.y} v0 ${topLeftCurve} h${ itemWidth - 2 * r } ${topRightCurve} v0 h-${itemHeight} z`, fill, hoverFill, x: bandPosition, y: height, width: itemWidth, }, to: { height: itemHeight, d: `m${to.x} ${to.y} v-${itemHeight} ${topLeftCurve} h${ itemWidth - 2 * r } ${topRightCurve} v${itemHeight} h-${itemWidth} z`, fill, hoverFill, x: bandPosition, y: height - itemHeight, width: itemWidth, }, config, }; };