Skip to content

Commit e74d5ae

Browse files
Scaling utilization Y axis (#1772)
* Use data for y scale, clamping at capacity * Normalize the mock data to sit within overall capacity * Adds a bit more variety in total utilization * Round `calculatedMaxValue` for better ticks * get rid of maxValue prop, simplify chart max calc --------- Co-authored-by: David Crespo <david.crespo@oxidecomputer.com>
1 parent a68c7c8 commit e74d5ae

File tree

3 files changed

+33
-23
lines changed

3 files changed

+33
-23
lines changed

app/components/SystemMetric.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ export function SystemMetric({
188188
interpolation="stepAfter"
189189
startTime={startTime}
190190
endTime={endTime}
191-
maxValue={capacity}
192191
unit={unit !== 'count' ? unit : undefined}
193192
/>
194193
</div>

app/components/TimeSeriesChart.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function renderTooltip(props: TooltipProps<number, string>, unit?: string) {
100100
)
101101
}
102102

103-
type Props = {
103+
type TimeSeriesChartProps = {
104104
className?: string
105105
data: ChartDatum[] | undefined
106106
title: string
@@ -109,10 +109,16 @@ type Props = {
109109
interpolation?: 'linear' | 'stepAfter'
110110
startTime: Date
111111
endTime: Date
112-
maxValue?: number
113112
unit?: string
114113
}
115114

115+
const TICK_COUNT = 6
116+
117+
/** Round `value` up to nearest number divisible by `divisor` */
118+
function roundUpToDivBy(value: number, divisor: number) {
119+
return Math.ceil(value / divisor) * divisor
120+
}
121+
116122
export default function TimeSeriesChart({
117123
className,
118124
data: rawData,
@@ -122,20 +128,23 @@ export default function TimeSeriesChart({
122128
interpolation = 'linear',
123129
startTime,
124130
endTime,
125-
maxValue,
126131
unit,
127-
}: Props) {
132+
}: TimeSeriesChartProps) {
133+
// We use the largest data point +20% for the graph scale. !rawData doesn't
134+
// mean it's empty (it will never be empty because we fill in artificial 0s at
135+
// beginning and end), it means the metrics requests haven't come back yet
136+
const maxY = useMemo(() => {
137+
if (!rawData) return null
138+
const dataMax = Math.max(...rawData.map((datum) => datum.value))
139+
return roundUpToDivBy(dataMax * 1.2, TICK_COUNT) // avoid uneven ticks
140+
}, [rawData])
141+
128142
// If max value is set we normalize the graph so that
129143
// is the maximum, we also use our own function as recharts
130-
// doesn't fill the whole domain (just upto the data max)
131-
const yTicks = maxValue
132-
? {
133-
domain: [0, maxValue],
134-
ticks: getVerticalTicks(6, maxValue),
135-
}
136-
: {
137-
tickSize: 6,
138-
}
144+
// doesn't fill the whole domain (just up to the data max)
145+
const yTicks = maxY
146+
? { domain: [0, maxY], ticks: getVerticalTicks(TICK_COUNT, maxY) }
147+
: undefined
139148

140149
// falling back here instead of in the parent lets us avoid causing a
141150
// re-render on every render of the parent when the data is undefined

libs/api-mocks/msw/util.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export function generateUtilization(
197197
const valueInterval = Math.floor(dataCount / timeInterval)
198198

199199
// Pick a reasonable start value
200-
const startVal = cap / 2
200+
const startVal = 500
201201
const values = new Array<number>(dataCount)
202202
values[0] = startVal
203203

@@ -213,15 +213,10 @@ export function generateUtilization(
213213
const threshold = i < 250 || (i > 500 && i < 750) ? 1 : 0.375
214214

215215
if (random < threshold) {
216-
const amount =
217-
metricName === 'cpus_provisioned'
218-
? 3
219-
: metricName === 'virtual_disk_space_provisioned'
220-
? TiB
221-
: TiB / 20
216+
const amount = 50
222217
offset = Math.floor(random * amount)
223218

224-
if (random < threshold / 3) {
219+
if (random < threshold / 2.5) {
225220
offset = offset * -1
226221
}
227222
}
@@ -237,7 +232,14 @@ export function generateUtilization(
237232
}
238233
}
239234

240-
return values
235+
// Find the current maximum value in the generated data
236+
const currentMax = Math.max(...values)
237+
238+
// Normalize the data to sit within the range of 0 to overall capacity
239+
const randomFactor = Math.random() * (1 - 0.33) + 0.33
240+
const normalizedValues = values.map((value) => (value / currentMax) * cap * randomFactor)
241+
242+
return normalizedValues
241243
}
242244

243245
type MetricParams = {

0 commit comments

Comments
 (0)