mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: Set better Chart Axis Bounds (#1585)
Closes HDX-3180 # Summary This PR makes a couple of changes to TimeChart axis bounds 1. Y Axis lower bound is now always 0 unless a series is selected (partial revert of #1572) 2. X-Axis bounds have been adjusted so that 1. There is no longer an empty partial interval's worth of space at the end of line charts 2. The first bar of a bar chart no longer overlaps with the Y Axis ## Before - The first Bar in bar charts overlaps the Y Axis <img width="1600" height="495" alt="Screenshot 2026-01-09 at 2 55 27 PM" src="https://github.com/user-attachments/assets/13087084-4847-46d5-98d3-85340101d7f3" /> - There is an empty partial (or full) interval at the end of charts <img width="1611" height="483" alt="Screenshot 2026-01-09 at 2 55 21 PM" src="https://github.com/user-attachments/assets/a286966b-ccfa-485c-8d26-7090f75120e0" /> - Y Axis lower bound is non-zero when no series are selected <img width="1603" height="388" alt="Screenshot 2026-01-09 at 2 38 54 PM" src="https://github.com/user-attachments/assets/4ca2743a-d484-40b1-b2e6-352aad838070" /> <img width="1623" height="373" alt="Screenshot 2026-01-09 at 2 37 26 PM" src="https://github.com/user-attachments/assets/4a8b9490-9efb-4c75-93b4-edb3321ee0a2" /> ## After - Bars fit fully within the chart domain <img width="1610" height="503" alt="Screenshot 2026-01-09 at 2 55 42 PM" src="https://github.com/user-attachments/assets/42ab1f62-4c1e-475f-b3be-4bf6ed147dc4" /> - There is no empty space at the end of the line charts - Y Axis lower bound is always 0 when no series are selected <img width="1613" height="490" alt="Screenshot 2026-01-09 at 2 55 50 PM" src="https://github.com/user-attachments/assets/ed723a99-2a24-47f2-8ac8-93901f7fbf88" />
This commit is contained in:
parent
99863885d0
commit
1e6987e485
3 changed files with 43 additions and 7 deletions
5
.changeset/long-pumas-draw.md
Normal file
5
.changeset/long-pumas-draw.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@hyperdx/app": patch
|
||||
---
|
||||
|
||||
fix: Set better Chart Axis Bounds
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { memo, useCallback, useId, useMemo, useRef, useState } from 'react';
|
||||
import cx from 'classnames';
|
||||
import { add, isSameSecond, sub } from 'date-fns';
|
||||
import { withErrorBoundary } from 'react-error-boundary';
|
||||
import {
|
||||
Area,
|
||||
|
|
@ -16,6 +17,7 @@ import {
|
|||
XAxis,
|
||||
YAxis,
|
||||
} from 'recharts';
|
||||
import { AxisDomain } from 'recharts/types/util/types';
|
||||
import { DisplayType } from '@hyperdx/common-utils/dist/types';
|
||||
import { Popover } from '@mantine/core';
|
||||
import { notifications } from '@mantine/notifications';
|
||||
|
|
@ -24,7 +26,11 @@ import { IconCaretDownFilled, IconCaretUpFilled } from '@tabler/icons-react';
|
|||
import type { NumberFormat } from '@/types';
|
||||
import { COLORS, formatNumber, truncateMiddle } from '@/utils';
|
||||
|
||||
import { LineData } from './ChartUtils';
|
||||
import {
|
||||
convertGranularityToSeconds,
|
||||
LineData,
|
||||
toStartOfInterval,
|
||||
} from './ChartUtils';
|
||||
import { FormatTime, useFormatTime } from './useFormatTime';
|
||||
|
||||
import styles from '../styles/HDXLineChart.module.scss';
|
||||
|
|
@ -404,6 +410,8 @@ export const MemoChart = memo(function MemoChart({
|
|||
previousPeriodOffsetSeconds,
|
||||
selectedSeriesNames,
|
||||
onToggleSeries,
|
||||
granularity,
|
||||
dateRangeEndInclusive = true,
|
||||
}: {
|
||||
graphResults: any[];
|
||||
setIsClickActive: (v: any) => void;
|
||||
|
|
@ -421,6 +429,8 @@ export const MemoChart = memo(function MemoChart({
|
|||
previousPeriodOffsetSeconds?: number;
|
||||
selectedSeriesNames?: Set<string>;
|
||||
onToggleSeries?: (seriesName: string, isShiftKey?: boolean) => void;
|
||||
granularity: string;
|
||||
dateRangeEndInclusive?: boolean;
|
||||
}) {
|
||||
const _id = useId();
|
||||
const id = _id.replace(/:/g, '');
|
||||
|
|
@ -495,12 +505,12 @@ export const MemoChart = memo(function MemoChart({
|
|||
});
|
||||
}, [lineData, displayType, id, isHovered, selectedSeriesNames]);
|
||||
|
||||
const yAxisDomain = useMemo(() => {
|
||||
const yAxisDomain: AxisDomain = useMemo(() => {
|
||||
const hasSelection = selectedSeriesNames && selectedSeriesNames.size > 0;
|
||||
|
||||
if (!hasSelection) {
|
||||
// No selection, let Recharts auto-calculate based on all data
|
||||
return ['auto', 'auto'];
|
||||
return [0, 'auto'];
|
||||
}
|
||||
|
||||
// When series are selected, calculate domain based only on visible series
|
||||
|
|
@ -574,6 +584,28 @@ export const MemoChart = memo(function MemoChart({
|
|||
return map;
|
||||
}, [lineData]);
|
||||
|
||||
const xAxisDomain: AxisDomain = useMemo(() => {
|
||||
let startTime = toStartOfInterval(dateRange[0], granularity);
|
||||
let endTime = toStartOfInterval(dateRange[1], granularity);
|
||||
const endTimeIsBoundaryAligned = isSameSecond(dateRange[1], endTime);
|
||||
if (endTimeIsBoundaryAligned && !dateRangeEndInclusive) {
|
||||
endTime = sub(endTime, {
|
||||
seconds: convertGranularityToSeconds(granularity),
|
||||
});
|
||||
}
|
||||
|
||||
// For bar charts, extend the domain in both directions by half a granularity unit
|
||||
// so that the full bar width is within the bounds of the chart
|
||||
if (displayType === DisplayType.StackedBar) {
|
||||
const halfGranularitySeconds =
|
||||
convertGranularityToSeconds(granularity) / 2;
|
||||
startTime = sub(startTime, { seconds: halfGranularitySeconds });
|
||||
endTime = add(endTime, { seconds: halfGranularitySeconds });
|
||||
}
|
||||
|
||||
return [startTime.getTime() / 1000, endTime.getTime() / 1000];
|
||||
}, [dateRange, granularity, dateRangeEndInclusive, displayType]);
|
||||
|
||||
return (
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
|
|
@ -708,10 +740,7 @@ export const MemoChart = memo(function MemoChart({
|
|||
)}
|
||||
<XAxis
|
||||
dataKey={timestampKey ?? 'ts_bucket'}
|
||||
domain={[
|
||||
dateRange[0].getTime() / 1000,
|
||||
dateRange[1].getTime() / 1000,
|
||||
]}
|
||||
domain={xAxisDomain}
|
||||
interval="preserveStartEnd"
|
||||
scale="time"
|
||||
type="number"
|
||||
|
|
|
|||
|
|
@ -750,6 +750,8 @@ function DBTimeChartComponent({
|
|||
previousPeriodOffsetSeconds={previousPeriodOffsetSeconds}
|
||||
selectedSeriesNames={selectedSeriesSet}
|
||||
onToggleSeries={handleToggleSeries}
|
||||
granularity={granularity}
|
||||
dateRangeEndInclusive={queriedConfig.dateRangeEndInclusive}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue