Skip to content

Commit 2ffc75a

Browse files
committed
Find the right tick spacings
1 parent f7f09ff commit 2ffc75a

File tree

2 files changed

+53
-46
lines changed

2 files changed

+53
-46
lines changed

site/src/modules/workspaces/WorkspaceTiming/Chart/Chart.tsx

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,13 @@ import {
1919
} from "./constants";
2020
import { Bar } from "./Bar";
2121

22-
// When displaying the chart we must consider the time intervals to display the
23-
// data. For example, if the total time is 10 seconds, we should display the
24-
// data in 200ms intervals. However, if the total time is 1 minute, we should
25-
// display the data in 5 seconds intervals. To achieve this, we define the
26-
// dimensions object that contains the time intervals for the chart.
27-
const dimensions = {
28-
small: 500,
29-
default: 5_000,
30-
};
31-
32-
export type ChartProps = {
33-
data: DataSection[];
34-
onBarClick: (label: string, section: string) => void;
35-
};
36-
37-
// This chart can split data into sections. Eg. display the provisioning timings
38-
// in one section and the scripting time in another
22+
// Data can be divided into sections. For example, display the provisioning
23+
// timings in one section and the scripting timings in another.
3924
type DataSection = {
4025
name: string;
4126
timings: Timing[];
4227
};
4328

44-
// Useful to perform chart operations without requiring additional information
45-
// such as labels or counts, which are only used for display purposes.
46-
export type Duration = {
47-
startedAt: Date;
48-
endedAt: Date;
49-
};
50-
5129
export type Timing = Duration & {
5230
/**
5331
* Label that will be displayed on the Y axis.
@@ -59,31 +37,43 @@ export type Timing = Duration & {
5937
* clearly indicate to the user that the timing encompasses multiple time
6038
* blocks.
6139
*/
62-
count: number;
40+
childrenCount: number;
41+
};
42+
43+
// Extracts the 'startedAt' and 'endedAt' date fields from the main Timing type.
44+
// This is useful for performing chart operations without needing additional
45+
// information like labels or children count, which are only used for display
46+
// purposes.
47+
export type Duration = {
48+
startedAt: Date;
49+
endedAt: Date;
50+
};
51+
52+
export type ChartProps = {
53+
data: DataSection[];
54+
onBarClick: (label: string, section: string) => void;
6355
};
6456

6557
export const Chart: FC<ChartProps> = ({ data, onBarClick }) => {
6658
const totalDuration = duration(data.flatMap((d) => d.timings));
6759
const totalTime = durationTime(totalDuration);
68-
// Use smaller dimensions for the chart if the total time is less than 10
69-
// seconds; otherwise, use default intervals.
70-
const dimension = totalTime < 10_000 ? dimensions.small : dimensions.default;
71-
72-
// XAxis intervals
73-
const intervalsCount = Math.ceil(totalTime / dimension);
74-
const intervals = Array.from(
75-
{ length: intervalsCount },
76-
(_, i) => i * dimension + dimension,
60+
61+
// XAxis ticks
62+
const tickSpacing = calcTickSpacing(totalTime);
63+
const ticksCount = Math.ceil(totalTime / tickSpacing);
64+
const ticks = Array.from(
65+
{ length: ticksCount },
66+
(_, i) => i * tickSpacing + tickSpacing,
7767
);
7868

79-
// Helper function to convert time into pixel size, used for setting bar width
80-
// and offset
69+
// Helper function to convert the tick spacing into pixel size. This is used
70+
// for setting the bar width and offset.
8171
const calcSize = (time: number): number => {
82-
return (columnWidth * time) / dimension;
72+
return (columnWidth * time) / tickSpacing;
8373
};
8474

8575
const formatTime = (time: number): string => {
86-
if (dimension === dimensions.small) {
76+
if (tickSpacing <= 1_000) {
8777
return `${time.toLocaleString()}ms`;
8878
}
8979
return `${(time / 1_000).toLocaleString(undefined, {
@@ -112,7 +102,7 @@ export const Chart: FC<ChartProps> = ({ data, onBarClick }) => {
112102
</YAxis>
113103

114104
<div css={styles.main}>
115-
<XAxis labels={intervals.map(formatTime)} />
105+
<XAxis labels={ticks.map(formatTime)} />
116106
<div css={styles.content}>
117107
{data.map((section) => {
118108
return (
@@ -129,16 +119,16 @@ export const Chart: FC<ChartProps> = ({ data, onBarClick }) => {
129119
afterLabel={formatTime(durationTime(t))}
130120
aria-labelledby={`${t.label}-label`}
131121
ref={applyBarHeightToLabel}
132-
disabled={t.count <= 1}
122+
disabled={t.childrenCount <= 1}
133123
onClick={() => {
134-
if (t.count <= 1) {
124+
if (t.childrenCount <= 1) {
135125
return;
136126
}
137127
onBarClick(t.label, section.name);
138128
}}
139129
>
140-
{t.count > 1 && (
141-
<TimingBlocks size={size} count={t.count} />
130+
{t.childrenCount > 1 && (
131+
<TimingBlocks size={size} count={t.childrenCount} />
142132
)}
143133
</Bar>
144134
);
@@ -147,13 +137,30 @@ export const Chart: FC<ChartProps> = ({ data, onBarClick }) => {
147137
);
148138
})}
149139

150-
<XGrid columns={intervals.length} />
140+
<XGrid columns={ticks.length} />
151141
</div>
152142
</div>
153143
</div>
154144
);
155145
};
156146

147+
// When displaying the chart we must consider the time intervals to display the
148+
// data. For example, if the total time is 10 seconds, we should display the
149+
// data in 200ms intervals. However, if the total time is 1 minute, we should
150+
// display the data in 5 seconds intervals. To achieve this, we define the
151+
// dimensions object that contains the time intervals for the chart.
152+
const tickSpacings = [100, 500, 5_000];
153+
154+
const calcTickSpacing = (totalTime: number): number => {
155+
const spacings = tickSpacings.slice().reverse();
156+
for (const s of spacings) {
157+
if (totalTime > s) {
158+
return s;
159+
}
160+
}
161+
return spacings[0];
162+
};
163+
157164
// Ensures the sidebar label remains vertically aligned with its corresponding bar.
158165
const applyBarHeightToLabel = (bar: HTMLDivElement | null) => {
159166
if (!bar) {

site/src/modules/workspaces/WorkspaceTiming/WorkspaceTimings.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export const selectChartData = (
102102
const stageDuration = duration(durations);
103103
const stageTiming: Timing = {
104104
label: stage.name,
105-
count: durations.length,
105+
childrenCount: durations.length,
106106
...stageDuration,
107107
};
108108
return stageTiming;
@@ -125,7 +125,7 @@ export const selectChartData = (
125125
.map((t) => {
126126
return {
127127
label: t.resource,
128-
count: 0, // Resource timings don't have inner timings
128+
childrenCount: 0, // Resource timings don't have inner timings
129129
...extractDuration(t),
130130
} as Timing;
131131
});

0 commit comments

Comments
 (0)