import React, { useCallback, useMemo, useState } from 'react'; import type { LayoutChangeEvent } from 'react-native'; import Svg from 'react-native-svg'; import { useTheme } from '../../../theme'; import Box from '../../Box'; import type { AxisCoordinates, HeaderConfig, XAxisConfig, YAxisConfig, } from '../types'; import ChartHeader from './ChartHeader'; import EmptyState from './EmptyState'; import XAxis from './XAxis'; import XAxisGrid from './XAxisGrid'; import YAxis from './YAxis'; import YAxisGrid from './YAxisGrid'; export type ChartFrameProps = { isEmpty?: boolean; xAxisConfig: XAxisConfig; yAxisConfig: YAxisConfig; headerConfig?: HeaderConfig; width: number; height: number; renderContent: (props: { coordinates: AxisCoordinates }) => React.ReactNode; /** * Text to display when the chart has no data (empty state). * If undefined, no empty label will appear even if the chart is empty. */ emptyText?: string; /** * If true, hides the grid lines for the Y-axis. * Defaults to false. */ hideYAxisGrid?: boolean; /** * If true, hides the grid lines for the X-axis. * Defaults to false. */ hideXAxisGrid?: boolean; }; const yStart = 0; const ChartFrame = ({ xAxisConfig, yAxisConfig, width, height, headerConfig, renderContent, isEmpty, emptyText, hideYAxisGrid = false, hideXAxisGrid = false, }: ChartFrameProps) => { const theme = useTheme(); const { title, actionsExtra } = headerConfig || {}; const [headerHeight, setHeaderHeight] = useState(0); const onHeaderLayout = useCallback((event: LayoutChangeEvent) => { setHeaderHeight(event.nativeEvent.layout.height); }, []); // Sizing and coordinates setup const { space: { yAxisGridTextMarginRight, xAxisGridTextMarginTop, headerMarginBottom, }, sizes: { yAxisDefaultTextWidth, xAxisDefaultTextHeight, yAxisDefaultTextHeight, }, } = theme.__hd__.chart; // Drawable height for the whole chart: content, axis, grid, etc. const chartContentHeight = height - headerHeight - (headerHeight > 0 ? headerMarginBottom : 0); // Start offsets for various chart components, after accounting for the charts axis text size const xStartOffset = yAxisDefaultTextWidth + yAxisGridTextMarginRight; const yStartOffset = xAxisDefaultTextHeight + xAxisGridTextMarginTop; const coordinates = useMemo( () => ({ yStart, yEnd: yStart + chartContentHeight - yStartOffset, xStart: xStartOffset, xEnd: width, }), [chartContentHeight, yStartOffset, xStartOffset, width] ); return ( {headerConfig && ( )} {!hideXAxisGrid && ( )} {!hideYAxisGrid && ( )} {/** Chart data component */} {/* If the chart is empty and emptyText is provided, show the empty state text. If emptyText is undefined, the empty label will not appear. */} {!isEmpty ? renderContent({ coordinates }) : emptyText && ( )} ); }; export default ChartFrame;