waveform-analysis 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +535 -575
- package/dist/types/components/core/layout.d.ts +2 -4
- package/dist/types/components/core/types.d.ts +0 -3
- package/dist/types/utils/formatters.d.ts +9 -10
- package/dist/types/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/core/layout.test.ts +7 -8
- package/src/components/core/layout.ts +10 -20
- package/src/components/core/trackLayoutBuilder.ts +4 -23
- package/src/components/core/types.ts +0 -3
- package/src/components/core/useWaveformLayout.ts +5 -27
- package/src/components/interaction/WaveformTooltip.test.ts +16 -0
- package/src/components/interaction/useWaveformZoom.ts +12 -8
- package/src/components/rendering/WaveformTrackAxes.vue +4 -26
- package/src/components/waveformChartCases/compactAndSharedHover.test.ts +7 -7
- package/src/components/waveformChartCases/dataAndHoverPerformance.test.ts +2 -2
- package/src/components/waveformChartCases/dataLifecycle.test.ts +4 -4
- package/src/components/waveformChartCases/frameGridAndFormatting.test.ts +29 -22
- package/src/components/waveformChartCases/interactionAndAnnotationCreation.test.ts +1 -1
- package/src/components/waveformChartCases/layoutAndDomains.test.ts +16 -14
- package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +8 -8
- package/src/components/waveformChartCases/presentationAndAxes.test.ts +6 -4
- package/src/components/waveformChartCases/presentationMode.test.ts +1 -1
- package/src/components/waveformChartCases/viewportBoxAndPan.test.ts +15 -0
- package/src/components/waveformChartCases/viewportConstraintsAndReset.test.ts +59 -11
- package/src/components/waveformChartCases/wheelZoomOut.test.ts +114 -0
- package/src/utils/formatters.test.ts +40 -31
- package/src/utils/formatters.ts +45 -45
- package/src/utils/index.ts +0 -1
package/src/utils/formatters.ts
CHANGED
|
@@ -4,22 +4,28 @@
|
|
|
4
4
|
export type TimeUnit = 'ms' | 's'
|
|
5
5
|
|
|
6
6
|
export interface ScientificAxisLabelOptions {
|
|
7
|
+
/** @deprecated Y-axis labels always use five significant digits before localization. */
|
|
7
8
|
precision?: number
|
|
8
9
|
axisMin?: number
|
|
9
10
|
axisMax?: number
|
|
11
|
+
topTickValue?: number
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
/** @deprecated Use ScientificAxisLabelOptions. */
|
|
13
|
-
export type ScientificYAxisLabelOptions = ScientificAxisLabelOptions
|
|
14
|
-
topTickValue?: number
|
|
15
|
-
}
|
|
15
|
+
export type ScientificYAxisLabelOptions = ScientificAxisLabelOptions
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
17
|
+
const SCIENTIFIC_MIN_ABSOLUTE_VALUE = 0.001
|
|
18
|
+
const SCIENTIFIC_MAX_PLAIN_ABSOLUTE_VALUE = 1000
|
|
19
|
+
const Y_AXIS_NUMBER_FORMATTER = new Intl.NumberFormat('zh-CN', {
|
|
20
|
+
maximumFractionDigits: 4,
|
|
21
|
+
})
|
|
20
22
|
const TOOLTIP_NUMBER_FORMATTER = new Intl.NumberFormat('zh-CN', {
|
|
21
23
|
maximumFractionDigits: 4,
|
|
22
24
|
})
|
|
25
|
+
const X_AXIS_TIME_FORMATTER = new Intl.NumberFormat('zh-CN', {
|
|
26
|
+
maximumFractionDigits: 0,
|
|
27
|
+
useGrouping: false,
|
|
28
|
+
})
|
|
23
29
|
|
|
24
30
|
function formatFixedNumber(value: number, precision: number): string {
|
|
25
31
|
const formatted = value.toFixed(Math.max(0, precision))
|
|
@@ -38,9 +44,10 @@ export function shouldUseScientificAxisLabel(maxAbsoluteValue: number): boolean
|
|
|
38
44
|
export function resolveScientificAxisExponent(axisMin?: number, axisMax?: number): number | null {
|
|
39
45
|
if (typeof axisMin !== 'number' || typeof axisMax !== 'number') return null
|
|
40
46
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
const maxValue = Math.max(axisMin, axisMax)
|
|
48
|
+
const absoluteMaxValue = Math.abs(maxValue)
|
|
49
|
+
return shouldUseScientificAxisLabel(absoluteMaxValue)
|
|
50
|
+
? Math.floor(Math.log10(absoluteMaxValue))
|
|
44
51
|
: null
|
|
45
52
|
}
|
|
46
53
|
|
|
@@ -49,6 +56,13 @@ function formatExponent(exponent: number): string {
|
|
|
49
56
|
return `E${sign}${Math.abs(exponent).toString().padStart(2, '0')}`
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
function formatYAxisNumber(value: number): string {
|
|
60
|
+
if (Object.is(value, -0)) return '0'
|
|
61
|
+
const roundedValue = value === 0 ? 0 : Number(value.toPrecision(5))
|
|
62
|
+
const formatted = Y_AXIS_NUMBER_FORMATTER.format(roundedValue)
|
|
63
|
+
return formatted === '-0' ? '0' : formatted
|
|
64
|
+
}
|
|
65
|
+
|
|
52
66
|
/** Format a Y-axis tick, sharing one exponent derived from the complete axis domain. */
|
|
53
67
|
export function formatScientificAxisLabel(
|
|
54
68
|
value: number,
|
|
@@ -56,10 +70,13 @@ export function formatScientificAxisLabel(
|
|
|
56
70
|
): string {
|
|
57
71
|
if (!Number.isFinite(value)) return String(value)
|
|
58
72
|
|
|
59
|
-
const precision = options.precision ?? DEFAULT_Y_AXIS_PRECISION
|
|
60
73
|
const exponent = resolveScientificAxisExponent(options.axisMin, options.axisMax)
|
|
61
74
|
const scaledValue = exponent === null ? value : value / 10 ** exponent
|
|
62
|
-
|
|
75
|
+
const formattedValue = formatYAxisNumber(scaledValue)
|
|
76
|
+
const topTickValue = options.topTickValue ?? options.axisMax
|
|
77
|
+
return exponent !== null && value === topTickValue
|
|
78
|
+
? `${formatExponent(exponent)} ${formattedValue}`
|
|
79
|
+
: formattedValue
|
|
63
80
|
}
|
|
64
81
|
|
|
65
82
|
/** Return the shared E-style multiplier for an axis, or null for a plain axis. */
|
|
@@ -86,6 +103,13 @@ export function formatTooltipNumber(value: number): string {
|
|
|
86
103
|
return TOOLTIP_NUMBER_FORMATTER.format(value)
|
|
87
104
|
}
|
|
88
105
|
|
|
106
|
+
/** Format an X-axis time value as a plain integer without grouping separators. */
|
|
107
|
+
function formatAxisTimeValue(value: number): string {
|
|
108
|
+
if (!Number.isFinite(value)) return String(value)
|
|
109
|
+
const formatted = X_AXIS_TIME_FORMATTER.format(value)
|
|
110
|
+
return formatted === '-0' ? '0' : formatted
|
|
111
|
+
}
|
|
112
|
+
|
|
89
113
|
/** Convert a number to complete plain decimal text without forcing exponential notation. */
|
|
90
114
|
export function formatPlainNumber(value: number): string {
|
|
91
115
|
if (!Number.isFinite(value)) return String(value)
|
|
@@ -134,54 +158,34 @@ export function endpointFractionDigits(domain: [number, number], timeUnit: TimeU
|
|
|
134
158
|
}
|
|
135
159
|
|
|
136
160
|
/**
|
|
137
|
-
*
|
|
161
|
+
* 将 X 轴端点时间格式化为当前显示单位下的普通整数
|
|
138
162
|
* @param value 时间值(秒)
|
|
139
|
-
* @param
|
|
163
|
+
* @param _domain 数据域(为保持现有调用签名而保留)
|
|
140
164
|
* @param timeUnit 时间单位
|
|
141
165
|
* @returns 格式化的时间字符串
|
|
142
166
|
*/
|
|
143
167
|
export function formatEndpointTime(
|
|
144
168
|
value: number,
|
|
145
|
-
|
|
169
|
+
_domain: [number, number],
|
|
146
170
|
timeUnit: TimeUnit,
|
|
147
171
|
): string {
|
|
148
|
-
|
|
149
|
-
number,
|
|
150
|
-
number,
|
|
151
|
-
]
|
|
152
|
-
return formatScientificAxisLabel(displayTime(value, timeUnit), {
|
|
153
|
-
axisMin,
|
|
154
|
-
axisMax,
|
|
155
|
-
})
|
|
172
|
+
return formatAxisTimeValue(displayTime(value, timeUnit))
|
|
156
173
|
}
|
|
157
174
|
|
|
158
175
|
/**
|
|
159
|
-
*
|
|
176
|
+
* 将 X 轴时间刻度格式化为当前显示单位下的普通整数
|
|
160
177
|
* @param value 时间值(秒)
|
|
161
178
|
* @param timeUnit 时间单位
|
|
179
|
+
* @param _domain 数据域(为保持现有调用签名而保留)
|
|
162
180
|
* @returns 格式化的时间字符串
|
|
163
181
|
*/
|
|
164
182
|
export function formatAxisTime(
|
|
165
183
|
value: number,
|
|
166
184
|
timeUnit: TimeUnit,
|
|
167
|
-
|
|
185
|
+
_domain?: [number, number],
|
|
168
186
|
): string {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
[number, number] | undefined
|
|
172
|
-
return formatScientificAxisLabel(displayValue, {
|
|
173
|
-
axisMin: displayDomain?.[0],
|
|
174
|
-
axisMax: displayDomain?.[1],
|
|
175
|
-
})
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** Return the shared multiplier for an X-axis domain in its selected display unit. */
|
|
179
|
-
export function formatAxisTimeExponent(
|
|
180
|
-
domain: [number, number],
|
|
181
|
-
timeUnit: TimeUnit,
|
|
182
|
-
): string | null {
|
|
183
|
-
const [axisMin, axisMax] = domain.map((value) => displayTime(value, timeUnit)) as [number, number]
|
|
184
|
-
return formatScientificAxisExponent(axisMin, axisMax)
|
|
187
|
+
void _domain
|
|
188
|
+
return formatAxisTimeValue(displayTime(value, timeUnit))
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
/**
|
|
@@ -191,11 +195,7 @@ export function formatAxisTimeExponent(
|
|
|
191
195
|
* @returns 格式化的时间字符串
|
|
192
196
|
*/
|
|
193
197
|
export function formatTooltipTime(value: number, timeUnit: TimeUnit): string {
|
|
194
|
-
|
|
195
|
-
return displayValue.toLocaleString('zh-CN', {
|
|
196
|
-
minimumFractionDigits: 4,
|
|
197
|
-
maximumFractionDigits: 4,
|
|
198
|
-
})
|
|
198
|
+
return formatTooltipNumber(displayTime(value, timeUnit))
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
/** Format an annotation X coordinate in the selected display time unit. */
|