import { alpha, Box, useTheme } from '@mui/material'; import { animated, useSpring } from '@react-spring/web'; import { scaleLinear } from '@visx/scale'; import { Bar } from '@visx/shape'; import { Group, Tooltip } from '@visx/visx'; import { clamp, equals, flatten, head, pluck } from 'ramda'; import { useMemo, useRef } from 'react'; import { Tooltip as MuiTooltip } from '../../components/Tooltip'; import { margins } from '../common/margins'; import { formatMetricValueWithUnit, getMetricWithLatestData } from '../common/timeSeries'; import type { Metric } from '../common/timeSeries/models'; import { useTooltipStyles } from '../common/useTooltipStyles'; import { getColorFromDataAndTresholds } from '../common/utils'; import type { SingleBarProps } from './models'; import { barHeights, lineMargins } from './ThresholdLine'; import Thresholds, { groupMargin } from './Thresholds'; const AnimatedRect = animated('rect'); interface Props extends SingleBarProps { height: number; width: number; } const ResponsiveSingleBar = ({ data, thresholds, width, height, displayAsRaw, baseColor, size = 'medium', showLabels = true, max, direction = 'column', textWidth }: Props): JSX.Element => { const { classes } = useTooltipStyles(); const theme = useTheme(); // @ts-expect-error - suppressing pre-existing type mismatch const metric = getMetricWithLatestData(data) as Metric; const latestMetricData = head(metric.data) as number; const thresholdValues = thresholds.enabled ? flatten([ pluck('value', thresholds.warning), pluck('value', thresholds.critical) ]) : [0]; const adaptedMaxValue = max || Math.max( metric.maximum_value || 0, Math.max(...thresholdValues) * 1.1, head(metric.data) as number ); const { showTooltip, hideTooltip, tooltipOpen, tooltipData } = Tooltip.useTooltip(); const svgRef = useRef(null); const barColor = useMemo( () => getColorFromDataAndTresholds({ baseColor, data: latestMetricData, theme, thresholds }), [latestMetricData, thresholds, theme, baseColor] ); const isSmall = equals(size, 'small'); const textStyle = isSmall ? theme.typography.h6 : theme.typography.h4; const textHeight = isSmall ? 46 : 27; const textY = useMemo(() => { if (direction === 'row' && isSmall) { return 2; } if (direction === 'row' && !isSmall) { return 22; } return isSmall ? 10 : 25; }, [direction, isSmall]); const text = showLabels && ( {formatMetricValueWithUnit({ base: 1000, isRaw: displayAsRaw, unit: metric.unit, value: metric.data[0] })} ); const widthMargin = useMemo( () => (direction === 'row' && textWidth) || 0, [direction, textWidth] ); const xScale = useMemo( () => scaleLinear({ domain: [0, adaptedMaxValue], range: [0, width - widthMargin - 10 || 0] }), [width, adaptedMaxValue, widthMargin] ); const metricBarWidth = useMemo( () => xScale(latestMetricData), [xScale, latestMetricData] ); const maxBarWidth = useMemo( () => xScale(adaptedMaxValue), [xScale, adaptedMaxValue] ); const springStyle = useSpring({ width: metricBarWidth }); const barY = direction === 'row' ? lineMargins[size] / 2 : groupMargin + (isSmall ? 0 : 2 * margins.top); const realBarHeight = !isSmall ? clamp( barHeights.small, barHeights.medium, height - textHeight - 2 * margins.top ) : barHeights.small; return (
single bar {text} {thresholds.enabled && ( )}
); }; export default ResponsiveSingleBar;