import * as React from 'react'; import {View, Text as TextNative} from 'react-native'; import {TailwindFn} from 'twrnc'; import {Style} from 'twrnc/dist/esm/types'; import Svg, {G, Rect, Text, SvgXml} from 'react-native-svg'; import CircleSvg from './icons/circle'; import Balloon, {BalloonData} from './Balloon'; const defaultColorsArray = ['#34D399', '#38BDF8', '#A78BFA']; type Value = { [key: string]: {amount: number; transactions: number}; }; type Values = { [key: string]: Value; }; export type Data = { values: Values; }; type Props = { tw: TailwindFn; data: Data; colorsArray?: string[]; style?: Style; labelingStyle?: Style; width: number; height: number; scaleSize: number; showLabels?: boolean; fontColor?: string; balloonData?: BalloonData; setBalloonData?: (valueId?: string | undefined) => void; notSelectedColor?: string; }; let selectionTimeout: NodeJS.Timeout; const VerticalBars = ({ tw, data, colorsArray = defaultColorsArray, style, labelingStyle, width, height, scaleSize, showLabels = true, fontColor = '#000000', balloonData, setBalloonData, notSelectedColor = '#D1D5DB', }: Props): JSX.Element => { const [barWidth, setBarWidth] = React.useState(0); const [scale, setScale] = React.useState(['0']); const [unitaryHeight, setUnitaryHeight] = React.useState(0); const [selectedColumn, setSelectedColumn] = React.useState(''); const [consumableColorsArray] = React.useState([...colorsArray].reverse()); const defaultStyles = tw`flex-1 font-medium text-base text-gray-500 items-center`; const chartDefaultStyles = tw``; const spaceBetween = 10; const labelHeight = 24; const scaleWidth = 50; let dx = scaleWidth; // Calculates the bar widths React.useEffect(() => { const valuesKeys = Object.keys(data.values); const numberOfColumns = valuesKeys.length; setBarWidth( (width - scaleWidth - (numberOfColumns - 1) * spaceBetween) / numberOfColumns, ); }, [width, data]); // Calculates the scale of the graph React.useEffect(() => { const ceilNumber = Math.ceil(scaleSize / 10) * 10; const head = parseInt(`${ceilNumber}`.substring(0, 1), 10); const step = head <= 5 ? ceilNumber / head : (ceilNumber / 2) * head; let suffix = ''; let divisor = 1; if (Math.floor(step / 1000000)) { suffix = 'M'; divisor = 1000000; } else if (Math.floor(step / 1000)) { suffix = 'k'; divisor = 1000; } const newScale = []; const numberOfLabels = ceilNumber / step; for (let i = 0; i < numberOfLabels; i += 1) { newScale.push(`${(i * step) / divisor}${suffix}`); } setScale(newScale); }, [scaleSize]); // Establishes the unitary height React.useEffect(() => { setUnitaryHeight(height / scaleSize); }, [height, scaleSize]); React.useEffect(() => { if (selectedColumn && setBalloonData) { setBalloonData(selectedColumn); clearTimeout(selectionTimeout); selectionTimeout = setTimeout(() => { setSelectedColumn(''); setBalloonData(); }, 5000); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedColumn]); return ( {/* Chart - Draws the SVG */} {scale.map((label, idx) => { return ( {`$${label}`} ); })} {Object.keys(data.values).map((key_, idx) => { const record = data.values[key_]; dx = idx > 0 ? dx + (barWidth + spaceBetween) : dx; let sum = 0; const l = Object.keys(record); for (let i = 0; i < l.length; i += 1) { sum += record[l[i]].amount; } let dy = height - labelHeight - sum * unitaryHeight; return ( setSelectedColumn(key_)}> {l.reverse().map((_, idx2: number) => { const originalDy = dy; const barHeight = unitaryHeight * record[l[idx2]].amount; dy = dy + barHeight; return ( ); })} {key_} ); })} {showLabels && ( {Object.keys(data.values[Object.keys(data.values)[0]]).map( (valueKey: string, idx: number) => { return ( {valueKey} ); }, )} )} {!!selectedColumn && balloonData && ( )} ); }; export default VerticalBars;