Skip to content

Commit 89bdb82

Browse files
committed
improved timeseries tooltip
1 parent 9b936f1 commit 89bdb82

4 files changed

Lines changed: 57 additions & 4 deletions

File tree

‎viewer/src/components/TimeSeries.jsx‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,14 @@ function TrajectoryChart({ signal, runs, chosen }) {
7474
)
7575
const { missing, magnitude, spec, error } = prepared
7676
const option = useMemo(
77-
() => trajectoryOptions(prepared.series, alignment, s.zoom),
77+
() =>
78+
trajectoryOptions(
79+
prepared.series,
80+
alignment,
81+
s.zoom,
82+
prepared.spec,
83+
prepared.magnitude,
84+
),
7885
[prepared, alignment, s.zoom],
7986
)
8087
return (

‎viewer/src/trajectory.js‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { summarizeTrajectories } from './uncertainty.js'
33
import { human } from './model.js'
44
import { inSelectionOrder } from './state.js'
55
import { displayUnit, inDisplayUnit, unitOptions } from './units.js'
6+
import { columnNumberFormat, formatNumber } from './numbers.js'
67
function trajectorySeries(study, current, supported, spec) {
78
const configColor = (config) => current.configColors[config.key]
89
const color = (run) =>
@@ -15,6 +16,7 @@ function trajectorySeries(study, current, supported, spec) {
1516
id: run.key,
1617
name: `${run.name}${run.record.parameters.seed == null ? '' : ` · seed ${run.record.parameters.seed}`}`,
1718
type: 'line',
19+
encode: { x: 0, y: 1, tooltip: [1] },
1820
step: 'end',
1921
showSymbol: false,
2022
connectNulls: false,
@@ -64,7 +66,7 @@ function trajectorySeries(study, current, supported, spec) {
6466
type: 'custom',
6567
silent: true,
6668
z: 1,
67-
encode: { x: [0, 3], y: [1, 2] },
69+
encode: { x: [0, 3], y: [1, 2], tooltip: [1, 2] },
6870
data: points
6971
.slice(0, -1)
7072
.flatMap((p, i) =>
@@ -99,6 +101,7 @@ function trajectorySeries(study, current, supported, spec) {
99101
id: `summary-${config.key}`,
100102
name: `${config.name} · ${human(s.timeStat)}`,
101103
type: 'line',
104+
encode: { x: 0, y: 1, tooltip: [1] },
102105
step: 'end',
103106
showSymbol: false,
104107
connectNulls: false,
@@ -172,10 +175,28 @@ export function prepareTrajectory(
172175
: trajectorySeries(study, settings, supported, spec)),
173176
}
174177
}
175-
export function trajectoryOptions(series, alignment, zoom) {
178+
export function trajectoryOptions(series, alignment, zoom, spec, magnitude) {
179+
const tooltipUnit = displayUnit(spec.unit, magnitude / spec.factor)
180+
const numberFormat = columnNumberFormat(
181+
magnitude / spec.factor / tooltipUnit.factor,
182+
)
183+
const formatValue = (value) => {
184+
const formatted = formatNumber(inDisplayUnit(value, tooltipUnit), numberFormat)
185+
return ['1', 'unknown'].includes(tooltipUnit.unit)
186+
? formatted
187+
: `${formatted} ${tooltipUnit.unit}`
188+
}
176189
return {
177190
useUTC: true,
178-
tooltip: { trigger: 'axis', renderMode: 'richText', confine: true },
191+
tooltip: {
192+
trigger: 'axis',
193+
renderMode: 'richText',
194+
confine: true,
195+
valueFormatter: (value) =>
196+
Array.isArray(value)
197+
? value.map(formatValue).join(' – ')
198+
: formatValue(value),
199+
},
179200
axisPointer: { link: [{ xAxisIndex: 'all' }] },
180201
grid: { top: 20, left: 80, right: 30, bottom: 75 },
181202
xAxis: {

‎viewer/tests/browser/react.spec.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ for (const [kind, base] of [
135135
).toBeCloseTo(20)
136136
await page.getByRole('button', { name: 'Time series', exact: true }).click()
137137
await expect(page.locator('.time-chart canvas')).toHaveCount(2)
138+
const hover = await page.locator('.time-chart').first().evaluate((el) => {
139+
const chart = (window as any).echarts.getInstanceByDom(el)
140+
chart.dispatchAction({ type: 'showTip', seriesIndex: 1, dataIndex: 0 })
141+
return chart.getOption().tooltip[0].valueFormatter(1234.567891234)
142+
})
143+
expect(hover).toBe('1,234.57 W')
138144
await page
139145
.getByRole('combobox', {
140146
name: 'Display unit for grid / Power',

‎viewer/tests/trajectory.test.mjs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { test } from 'node:test'
2+
import assert from 'node:assert/strict'
3+
import { trajectoryOptions } from '../src/trajectory.js'
4+
5+
test('trajectory tooltips use automatic units even when the axis unit is overridden', () => {
6+
const watts = trajectoryOptions([], 'elapsed', {}, { unit: 'W', factor: 1 }, 2e6)
7+
const kilowatts = trajectoryOptions([], 'elapsed', {}, { unit: 'kW', factor: 1000 }, 2e6)
8+
assert.equal(watts.tooltip.valueFormatter(1234567.891234), '1.23 MW')
9+
assert.equal(kilowatts.tooltip.valueFormatter(1234.567891234), '1.23 MW')
10+
assert.equal(watts.tooltip.valueFormatter(-1234567.891234), '-1.23 MW')
11+
assert.equal(watts.tooltip.valueFormatter([1234567.89, 1987654.32]), '1.23 MW – 1.99 MW')
12+
})
13+
14+
test('trajectory tooltips preserve fractions, missing values and small nonzero values', () => {
15+
const fraction = trajectoryOptions([], 'elapsed', {}, { unit: '1', factor: 1 }, 1)
16+
assert.equal(fraction.tooltip.valueFormatter(0.123456789), '0.12')
17+
assert.equal(fraction.tooltip.valueFormatter(null), '—')
18+
assert.equal(fraction.tooltip.valueFormatter(0.00001), '<0.01')
19+
})

0 commit comments

Comments
 (0)