Browse Source

ref(stats): Improve x-axis labels visibility (#76527)

Priscila Oliveira 6 months ago
parent
commit
611e3b960e

+ 9 - 14
static/app/views/organizationStats/usageChart/index.tsx

@@ -26,7 +26,7 @@ import {statsPeriodToDays} from 'sentry/utils/duration/statsPeriodToDays';
 
 import {formatUsageWithUnits} from '../utils';
 
-import {getTooltipFormatter, getXAxisDates, getXAxisLabelInterval} from './utils';
+import {getTooltipFormatter, getXAxisDates, getXAxisLabelVisibility} from './utils';
 
 const GIGABYTE = 10 ** 9;
 
@@ -253,8 +253,7 @@ function chartMetadata({
   chartLabel: React.ReactNode;
   tooltipValueFormatter: (val?: number) => string;
   xAxisData: string[];
-  xAxisLabelInterval: number;
-  xAxisTickInterval: number;
+  xAxisLabelVisibility: Record<number, boolean>;
   yAxisMinInterval: number;
 } {
   const selectDataCategory = categoryOptions.find(o => o.value === dataCategory);
@@ -287,11 +286,6 @@ function chartMetadata({
     throw new Error('UsageChart: Unable to parse data time period');
   }
 
-  const {xAxisTickInterval, xAxisLabelInterval} = getXAxisLabelInterval(
-    dataPeriod,
-    dataPeriod / barPeriod
-  );
-
   const {label, yAxisMinInterval} = selectDataCategory;
 
   /**
@@ -308,12 +302,13 @@ function chartMetadata({
     usageDateInterval
   );
 
+  const {xAxisLabelVisibility} = getXAxisLabelVisibility(dataPeriod, xAxisDates);
+
   return {
     chartLabel: label,
     chartData,
     xAxisData: xAxisDates,
-    xAxisTickInterval,
-    xAxisLabelInterval,
+    xAxisLabelVisibility,
     yAxisMinInterval,
     tooltipValueFormatter: getTooltipFormatter(dataCategory),
   };
@@ -367,9 +362,8 @@ function UsageChartBody({
     chartData,
     tooltipValueFormatter,
     xAxisData,
-    xAxisTickInterval,
-    xAxisLabelInterval,
     yAxisMinInterval,
+    xAxisLabelVisibility,
   } = chartMetadata({
     categoryOptions,
     dataCategory,
@@ -485,11 +479,12 @@ function UsageChartBody({
         name: 'Date',
         data: xAxisData,
         axisTick: {
-          interval: xAxisTickInterval,
           alignWithLabel: true,
         },
         axisLabel: {
-          interval: xAxisLabelInterval,
+          interval: function (index: number) {
+            return xAxisLabelVisibility[index];
+          },
           formatter: (label: string) => label.slice(0, 6), // Limit label to 6 chars
         },
         theme,

+ 43 - 45
static/app/views/organizationStats/usageChart/utils.tsx

@@ -83,58 +83,56 @@ export function getTooltipFormatter(dataCategory: DataCategoryInfo['plural']) {
 const MAX_NUMBER_OF_LABELS = 10;
 
 /**
+ * Determines which X-axis labels should be visible based on data period and intervals.
  *
  * @param dataPeriod - Quantity of hours covered by the data
- * @param numBars - Quantity of data points covered by the dataPeriod
+ * @param intervals - Intervals to be displayed on the X-axis
+ * @returns An object containing an array indicating visibility of each X-axis label
  */
-export function getXAxisLabelInterval(dataPeriod: number, numBars: number) {
-  return dataPeriod > 7 * 24
-    ? getLabelIntervalLongPeriod(dataPeriod, numBars)
-    : getLabelIntervalShortPeriod(dataPeriod, numBars);
-}
-
-/**
- * @param dataPeriod - Quantity of hours covered by data, expected 7+ days
- */
-function getLabelIntervalLongPeriod(dataPeriod: number, numBars: number) {
-  const days = dataPeriod / 24;
-  if (days <= 7) {
-    throw new Error('This method should be used for periods > 7 days');
+export function getXAxisLabelVisibility(dataPeriod: number, intervals: string[]) {
+  if (dataPeriod <= 24) {
+    return {
+      xAxisLabelVisibility: Array(intervals.length).fill(false),
+    };
   }
 
-  // Use 1 tick per day
-  let numTicks = days;
-  let numLabels = numTicks;
-
-  const daysBetweenLabels = [2, 4, 7, 14];
-  const daysBetweenTicks = [1, 2, 7, 7];
-
-  for (let i = 0; i < daysBetweenLabels.length && numLabels > MAX_NUMBER_OF_LABELS; i++) {
-    numLabels = numTicks / daysBetweenLabels[i];
-    numTicks = days / daysBetweenTicks[i];
+  const uniqueLabels: Set<string> = new Set();
+  const labelToPositionMap: Map<string, number> = new Map();
+  const labelVisibility: boolean[] = new Array(intervals.length).fill(false);
+
+  // Collect unique labels and their positions
+  intervals.forEach((label, index) => {
+    if (index === 0 || label.slice(0, 6) !== intervals[index - 1].slice(0, 6)) {
+      uniqueLabels.add(label);
+      labelToPositionMap.set(label, index);
+    }
+  });
+
+  const totalUniqueLabels = uniqueLabels.size;
+
+  // Determine which labels should be visible
+  if (totalUniqueLabels <= MAX_NUMBER_OF_LABELS) {
+    uniqueLabels.forEach(label => {
+      const position = labelToPositionMap.get(label);
+      if (position !== undefined) {
+        labelVisibility[position] = true;
+      }
+    });
+    return {xAxisLabelVisibility: labelVisibility};
   }
 
-  return {
-    xAxisTickInterval: numBars / numTicks - 1,
-    xAxisLabelInterval: numBars / numLabels - 1,
-  };
-}
-
-/**
- * @param dataPeriod - Quantity of hours covered by data, expected <7 days
- */
-function getLabelIntervalShortPeriod(dataPeriod: number, numBars: number) {
-  const days = dataPeriod / 24;
-  if (days > 7) {
-    throw new Error('This method should be used for periods <= 7 days');
-  }
+  const interval = Math.floor(totalUniqueLabels / MAX_NUMBER_OF_LABELS);
 
-  // Use 1 tick/label per day, since it's guaranteed to be 7 or less
-  const numTicks = days;
-  const interval = numBars / numTicks;
+  let i = 0;
+  uniqueLabels.forEach(label => {
+    if (i % interval === 0) {
+      const position = labelToPositionMap.get(label);
+      if (position !== undefined) {
+        labelVisibility[position] = true;
+      }
+    }
+    i++;
+  });
 
-  return {
-    xAxisTickInterval: interval - 1,
-    xAxisLabelInterval: interval - 1,
-  };
+  return {xAxisLabelVisibility: labelVisibility};
 }