import { ResponsiveContainer } from 'recharts'; import styled, { useTheme } from 'styled-components'; import { spacing, Stack, Wrap } from '../../../spacing'; import { Box } from '../../box/Box'; import { IconHelp } from '../../iconhelper/IconHelper'; import { Loader } from '../../loader/Loader.component'; import { Text } from '../../text/Text.component'; import { ConstrainedText } from '../../constrainedtext/Constrainedtext.component'; import { FormattedDateTime } from '../../date/FormattedDateTime'; import { formatXAxisDate, maxWidthTooltip } from './chartUtils'; import { TimeType, CategoryType } from '../types'; /** * Styled ResponsiveContainer for charts * Shared by Barchart and LineTimeSerieChart * Ensures tooltip overflow is visible and removes outline */ export const StyledResponsiveContainer = styled(ResponsiveContainer)` // Avoid tooltip over constrained text to be cut off & .recharts-surface { outline: none; overflow: visible; } `; const TickContainer = styled.div` width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; `; interface ChartLoadingOrErrorProps { height: number; } /** * Error state component for charts */ export const ChartError = ({ height }: ChartLoadingOrErrorProps) => { return ( Chart data is not available ); }; /** * Loading state component for charts */ export const ChartLoading = ({ height }: ChartLoadingOrErrorProps) => { return ( Loading Chart Data...} /> ); }; interface ChartHeaderProps { title?: string; secondaryTitle?: string; helpTooltip?: React.ReactNode; rightTitle?: React.ReactNode; isLoading?: boolean; } /** * Shared chart header component * Used by Barchart and LineTimeSerieChart */ export const ChartHeader = ({ title, secondaryTitle, helpTooltip, rightTitle, isLoading, }: ChartHeaderProps) => { return ( {title && {title}} {helpTooltip && ( )} {secondaryTitle && ( {secondaryTitle} )} {isLoading && } {rightTitle} ); }; interface CustomTickProps { x: number | string; y: number | string; payload: { value: number; }; visibleTicksCount?: number; width?: number | string; type: TimeType | CategoryType; tickWidthOffset?: number; } /** * Custom tick component for charts * Used by Barchart for time-based x-axis ticks */ export const CustomTick = ({ x, y, payload, visibleTicksCount, width, type, tickWidthOffset = 4, }: CustomTickProps) => { const theme = useTheme(); const numX = typeof x === 'string' ? parseFloat(x) : x; const numY = typeof y === 'string' ? parseFloat(y) : y; const numWidth = typeof width === 'string' ? parseFloat(width) : (width ?? 0); const tickCount = visibleTicksCount ?? 1; const tickWidth = numWidth / tickCount - tickWidthOffset; const centerX = numX - tickWidth / 2; const duration = type.type === 'time' ? (type.timeRange.endDate.getTime() - type.timeRange.startDate.getTime()) / 1000 : 0; return ( {type.type === 'time' ? ( ) : ( String(payload.value) )} } centered tooltipStyle={{ backgroundColor: theme.backgroundLevel1, padding: spacing.r10, borderRadius: spacing.r8, border: `1px solid ${theme.border}`, position: 'absolute', }} /> ); };