waveform-analysis 0.1.62 → 0.1.64

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.
Files changed (83) hide show
  1. package/README.md +9 -2
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +953 -946
  4. package/dist/style.css +1 -1
  5. package/dist/types/types/chart.d.ts +2 -1
  6. package/package.json +1 -1
  7. package/src/components/WaveformChart.vue +1 -1
  8. package/src/components/core/xDomain.ts +26 -2
  9. package/src/components/rendering/WaveformLegend.vue +1 -1
  10. package/src/components/rendering/WaveformSeriesLayer.vue +1 -1
  11. package/src/demo/DemoChartHost.vue +1 -0
  12. package/src/types/chart.ts +2 -1
  13. package/src/App.test.ts +0 -400
  14. package/src/components/annotation/components.test.ts +0 -372
  15. package/src/components/annotation/markup.test.ts +0 -371
  16. package/src/components/annotation/serialization.test.ts +0 -114
  17. package/src/components/core/constants.test.ts +0 -29
  18. package/src/components/core/fixedYDomainLayout.test.ts +0 -204
  19. package/src/components/core/grid.test.ts +0 -197
  20. package/src/components/core/latestTaskScheduler.test.ts +0 -51
  21. package/src/components/core/layout.test.ts +0 -373
  22. package/src/components/core/title.test.ts +0 -76
  23. package/src/components/core/useWaveformData.test.ts +0 -95
  24. package/src/components/core/useWaveformRenderSampling.test.ts +0 -17
  25. package/src/components/core/xDomain.test.ts +0 -28
  26. package/src/components/core/yAxisNice.test.ts +0 -174
  27. package/src/components/core/yAxisSlotLayout.test.ts +0 -165
  28. package/src/components/core/yDomain.test.ts +0 -56
  29. package/src/components/interaction/WaveformTooltip.test.ts +0 -276
  30. package/src/components/interaction/viewportInteractionState.test.ts +0 -101
  31. package/src/components/utils/useAnimationFrameThrottle.test.ts +0 -53
  32. package/src/components/waveformChartCases/annotationEditingAndReprojection.test.ts +0 -257
  33. package/src/components/waveformChartCases/compactAndSharedHover.test.ts +0 -358
  34. package/src/components/waveformChartCases/dataAndHoverPerformance.test.ts +0 -358
  35. package/src/components/waveformChartCases/dataLifecycle.test.ts +0 -310
  36. package/src/components/waveformChartCases/frameGridAndFormatting.test.ts +0 -389
  37. package/src/components/waveformChartCases/gridFill.test.ts +0 -95
  38. package/src/components/waveformChartCases/incompleteDataHover.test.ts +0 -155
  39. package/src/components/waveformChartCases/interactionAndAnnotationCreation.test.ts +0 -328
  40. package/src/components/waveformChartCases/layoutAndDomains.test.ts +0 -371
  41. package/src/components/waveformChartCases/legendVisibility.test.ts +0 -350
  42. package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +0 -400
  43. package/src/components/waveformChartCases/multiAxisLabelAlignment.test.ts +0 -61
  44. package/src/components/waveformChartCases/presentationAndAxes.test.ts +0 -345
  45. package/src/components/waveformChartCases/presentationMode.test.ts +0 -327
  46. package/src/components/waveformChartCases/renderingStyles.test.ts +0 -283
  47. package/src/components/waveformChartCases/sizingAndTitles.test.ts +0 -370
  48. package/src/components/waveformChartCases/trackOrder.test.ts +0 -323
  49. package/src/components/waveformChartCases/viewportBoxAndPan.test.ts +0 -365
  50. package/src/components/waveformChartCases/viewportConstraintsAndReset.test.ts +0 -311
  51. package/src/components/waveformChartCases/viewportLifecycle.test.ts +0 -132
  52. package/src/components/waveformChartCases/viewportReset.test.ts +0 -251
  53. package/src/components/waveformChartCases/wheelZoomOut.test.ts +0 -114
  54. package/src/components/waveformChartCases/workerSamplingIntegration.test.ts +0 -117
  55. package/src/components/waveformChartCases/xDomainStrategy.test.ts +0 -168
  56. package/src/components/waveformChartCases/yAxisLayout.test.ts +0 -103
  57. package/src/components/waveformChartCases/zoomIntentAndDataRebind.test.ts +0 -213
  58. package/src/components/waveformChartCases/zoomPointConstraints.test.ts +0 -308
  59. package/src/components/waveformLegendGeometry.test.ts +0 -21
  60. package/src/components/waveformNormalization.test.ts +0 -170
  61. package/src/core/data.test.ts +0 -241
  62. package/src/core/rendering.test.ts +0 -267
  63. package/src/core/renderingStrategies.test.ts +0 -90
  64. package/src/core/samplingReference.test.ts +0 -124
  65. package/src/core/wasmSampling.test.ts +0 -205
  66. package/src/core/workerSampling/multiresolution.test.ts +0 -69
  67. package/src/core/workerSampling/protocol.test.ts +0 -34
  68. package/src/core/workerSampling/repository.test.ts +0 -400
  69. package/src/core/workerSampling/repositoryCache.test.ts +0 -163
  70. package/src/core/workerSampling/repositorySampling.test.ts +0 -106
  71. package/src/core/workerSampling/repositoryTypedDataset.test.ts +0 -89
  72. package/src/core/workerSampling/repositoryWasmDataset.test.ts +0 -70
  73. package/src/data/simulatedWaveforms.test.ts +0 -60
  74. package/src/demo/plotMarginControls.test.ts +0 -29
  75. package/src/demo/xAxisLabelControls.test.ts +0 -86
  76. package/src/test/setup.ts +0 -82
  77. package/src/test/waveformChart.ts +0 -75
  78. package/src/utils/domain.test.ts +0 -28
  79. package/src/utils/formatters.test.ts +0 -131
  80. package/src/utils/sampling.test.ts +0 -226
  81. package/src/views/FixedYDomainDemo.test.ts +0 -44
  82. package/src/views/WasmSamplingDemo.test.ts +0 -13
  83. package/src/views/wasmSamplingDemoSampling.test.ts +0 -27
@@ -1,400 +0,0 @@
1
- import { flushPromises } from '@vue/test-utils'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { flushAnimationFrames } from '../../test/setup'
5
- import { type WaveformData } from '../waveform'
6
-
7
- import { gridSeries, mountSizedChart } from '../../test/waveformChart'
8
-
9
- describe('WaveformChart', () => {
10
- it('resolves a separate scientific multiplier for every Y axis', async () => {
11
- const wrapper = await mountSizedChart(
12
- {
13
- kind: 'series',
14
- series: [
15
- {
16
- trackId: 'shared-frame',
17
- name: '普通量程',
18
- unit: 'V',
19
- data: {
20
- kind: 'points',
21
- points: [
22
- { x: 0, y: 0 },
23
- { x: 1, y: 1 },
24
- ],
25
- },
26
- },
27
- {
28
- trackId: 'shared-frame',
29
- name: '大量程',
30
- unit: 'A',
31
- data: {
32
- kind: 'points',
33
- points: [
34
- { x: 0, y: 0 },
35
- { x: 1, y: 2540 },
36
- ],
37
- },
38
- },
39
- {
40
- trackId: 'shared-frame',
41
- name: '小量程',
42
- unit: 'T',
43
- data: {
44
- kind: 'points',
45
- points: [
46
- { x: 0, y: 0 },
47
- { x: 1, y: 0.0002 },
48
- ],
49
- },
50
- },
51
- ],
52
- },
53
- { overlayMode: 'multi-axis' },
54
- )
55
-
56
- expect(
57
- wrapper.findAll('.waveform-chart__axis--y').map((axis) =>
58
- axis
59
- .findAll('.tick text')
60
- .map((label) => label.text())
61
- .filter((label) => label.startsWith('E')),
62
- ),
63
- ).toEqual([
64
- [],
65
- [expect.stringMatching(/^E\+03 \(A\) /)],
66
- [expect.stringMatching(/^E-04 \(T\) /)],
67
- ])
68
- })
69
-
70
- it('reprojects annotations with the Y axis assigned to their series', async () => {
71
- const data: WaveformData = {
72
- kind: 'series',
73
- series: [
74
- {
75
- id: 'low',
76
- trackId: 'shared-frame',
77
- name: '低量程',
78
- data: {
79
- kind: 'points',
80
- points: [
81
- { x: 0, y: 0 },
82
- { x: 1, y: 10 },
83
- ],
84
- },
85
- },
86
- {
87
- id: 'high',
88
- trackId: 'shared-frame',
89
- name: '高量程',
90
- data: {
91
- kind: 'points',
92
- points: [
93
- { x: 0, y: 1000 },
94
- { x: 1, y: 2000 },
95
- ],
96
- },
97
- },
98
- ],
99
- }
100
- const wrapper = await mountSizedChart(data, {
101
- annotations: [{ id: 'high-note', seriesId: 'high', x: 0.5, y: 1500, text: '高值' }],
102
- })
103
- const singleAxisY = wrapper.get('.waveform-annotation__arrow').attributes('y2')
104
-
105
- await wrapper.setProps({ overlayMode: 'multi-axis' })
106
- await flushPromises()
107
-
108
- expect(wrapper.get('.waveform-annotation__arrow').attributes('y2')).not.toBe(singleAxisY)
109
-
110
- wrapper.unmount()
111
- })
112
-
113
- it('paginates channels into a row-major two by one grid', async () => {
114
- const wrapper = await mountSizedChart(gridSeries(5), {
115
- grid: { rowCount: 2, columnCount: 1 },
116
- })
117
-
118
- expect(wrapper.findAll('.waveform-chart__track')).toHaveLength(2)
119
- expect(
120
- wrapper.findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
121
- ).toEqual(['channel-0', 'channel-1'])
122
- const previousButton = () => wrapper.get('.ant-pagination-prev button')
123
- const nextButton = () => wrapper.get('.ant-pagination-next button')
124
-
125
- expect(wrapper.get('.ant-pagination-item-1').classes()).toContain('ant-pagination-item-active')
126
- expect(wrapper.get('.ant-pagination-prev').classes()).toContain('ant-pagination-disabled')
127
-
128
- await nextButton().trigger('click')
129
- expect(
130
- wrapper.findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
131
- ).toEqual(['channel-2', 'channel-3'])
132
- expect(wrapper.emitted('page-change')?.at(-1)).toEqual([2, 3])
133
-
134
- await previousButton().trigger('click')
135
- expect(wrapper.get('.ant-pagination-item-1').classes()).toContain('ant-pagination-item-active')
136
- expect(wrapper.emitted('page-change')?.at(-1)).toEqual([1, 3])
137
-
138
- await nextButton().trigger('click')
139
- await nextButton().trigger('click')
140
- expect(
141
- wrapper.findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
142
- ).toEqual(['channel-4'])
143
- expect(wrapper.get('.ant-pagination-item-3').classes()).toContain('ant-pagination-item-active')
144
- expect(wrapper.get('.ant-pagination-next').classes()).toContain('ant-pagination-disabled')
145
- })
146
-
147
- it('keeps ordered empty tracks in their page slots after channels are merged', async () => {
148
- const wrapper = await mountSizedChart(
149
- {
150
- kind: 'series',
151
- series: ['frame-1', 'frame-1', 'frame-3', 'frame-4', 'frame-5', 'frame-6'].map(
152
- (trackId, index) => ({
153
- id: `channel-${index + 1}`,
154
- trackId,
155
- name: `channel-${index + 1}`,
156
- data: {
157
- kind: 'points' as const,
158
- points: [
159
- { x: 0, y: index },
160
- { x: 1, y: index + 1 },
161
- ],
162
- },
163
- }),
164
- ),
165
- },
166
- {
167
- grid: {
168
- rowCount: 2,
169
- columnCount: 1,
170
- trackOrder: ['frame-1', 'frame-2', 'frame-3', 'frame-4', 'frame-5', 'frame-6'],
171
- },
172
- },
173
- )
174
- const trackIds = () =>
175
- wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id'))
176
- const lineIds = () =>
177
- wrapper.findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id'))
178
- const nextButton = () => wrapper.get('.ant-pagination-next button')
179
-
180
- expect(trackIds()).toEqual(['frame-1', 'frame-2'])
181
- expect(wrapper.findAll('.waveform-chart__track--empty')).toHaveLength(1)
182
- expect(lineIds()).toEqual(['channel-1', 'channel-2'])
183
- expect(wrapper.findAll('.waveform-chart__legend')).toHaveLength(1)
184
-
185
- await nextButton().trigger('click')
186
- expect(trackIds()).toEqual(['frame-3', 'frame-4'])
187
- expect(lineIds()).toEqual(['channel-3', 'channel-4'])
188
- expect(wrapper.emitted('page-change')?.at(-1)).toEqual([2, 3])
189
-
190
- await nextButton().trigger('click')
191
- expect(trackIds()).toEqual(['frame-5', 'frame-6'])
192
- expect(lineIds()).toEqual(['channel-5', 'channel-6'])
193
- expect(wrapper.emitted('page-change')?.at(-1)).toEqual([3, 3])
194
- })
195
-
196
- it('overlays series with the same track ID without changing the next frame', async () => {
197
- const wrapper = await mountSizedChart(
198
- {
199
- kind: 'series',
200
- series: [
201
- {
202
- id: 'primary',
203
- trackId: 'frame-1',
204
- name: 'BT2_2M',
205
- data: {
206
- kind: 'points',
207
- points: [
208
- { x: 0, y: 0 },
209
- { x: 1, y: 1 },
210
- ],
211
- },
212
- },
213
- {
214
- id: 'second-frame',
215
- name: 'BT1_2M',
216
- data: {
217
- kind: 'points',
218
- points: [
219
- { x: 0, y: 2 },
220
- { x: 1, y: 3 },
221
- ],
222
- },
223
- },
224
- {
225
- id: 'comparison',
226
- trackId: 'frame-1',
227
- name: 'TEST_CH_1',
228
- data: {
229
- kind: 'points',
230
- points: [
231
- { x: 0, y: 0.5 },
232
- { x: 1, y: 1.5 },
233
- ],
234
- },
235
- },
236
- {
237
- id: 'reference',
238
- trackId: 'frame-1',
239
- name: 'REF_CH_1',
240
- data: {
241
- kind: 'points',
242
- points: [
243
- { x: 0, y: 0.25 },
244
- { x: 1, y: 1.25 },
245
- ],
246
- },
247
- },
248
- ],
249
- },
250
- { frameNumber: 1, grid: { rowCount: 2, columnCount: 1 } },
251
- )
252
-
253
- const tracks = wrapper.findAll('.waveform-chart__track')
254
- expect(tracks).toHaveLength(2)
255
- expect(
256
- tracks[0].findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
257
- ).toEqual(['primary', 'comparison', 'reference'])
258
- expect(
259
- tracks[1].findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
260
- ).toEqual(['second-frame'])
261
- expect(tracks[0].find('.waveform-chart__y-axis-label').exists()).toBe(false)
262
- expect(tracks[0].findAll('.waveform-chart__axis--y .tick').length).toBeGreaterThan(0)
263
- expect(tracks[1].get('.waveform-chart__y-axis-label').text()).toBe('BT1_2M')
264
- expect(wrapper.findAll('.waveform-chart__legend')).toHaveLength(1)
265
- const legend = wrapper.get('.waveform-chart__legend')
266
- expect(legend.attributes('data-position')).toBe('top-right')
267
- expect(legend.attributes('data-orientation')).toBe('vertical')
268
- expect(legend.get('.waveform-legend__panel').attributes('style')).toContain(
269
- 'background-color: rgba(255, 255, 255, 0.7)',
270
- )
271
- expect(legend.findAll('.waveform-chart__legend-item').map((item) => item.text())).toEqual([
272
- 'BT2_2M',
273
- 'TEST_CH_1',
274
- 'REF_CH_1',
275
- ])
276
- expect(
277
- legend
278
- .findAll('.waveform-legend__swatch')
279
- .map((swatch) => swatch.get('path').attributes('stroke')),
280
- ).toEqual(['#0960bd', '#2ca02c', '#d62728'])
281
- expect(wrapper.findAll('.waveform-chart__watermark').map((item) => item.text())).toEqual([
282
- '1',
283
- '2',
284
- ])
285
- expect(wrapper.find('.ant-pagination').exists()).toBe(false)
286
-
287
- const firstTrackOverlay = tracks[0].get('.waveform-chart__overlay')
288
- const overlayWidth = Number(firstTrackOverlay.attributes('width'))
289
- const overlayHeight = Number(firstTrackOverlay.attributes('height'))
290
- Object.defineProperty(firstTrackOverlay.element, 'getBoundingClientRect', {
291
- value: () => ({ left: 0, top: 0, width: overlayWidth, height: overlayHeight }),
292
- })
293
- firstTrackOverlay.element.dispatchEvent(
294
- new MouseEvent('pointermove', {
295
- clientX: overlayWidth / 2,
296
- clientY: overlayHeight / 2,
297
- bubbles: true,
298
- }),
299
- )
300
- flushAnimationFrames()
301
- await flushPromises()
302
-
303
- const tooltipSeries = wrapper.findAll('.waveform-chart__tooltip-series')
304
- expect(tooltipSeries).toHaveLength(3)
305
- expect(tooltipSeries.map((item) => item.text())).toEqual([
306
- expect.stringContaining('BT2_2M'),
307
- expect.stringContaining('TEST_CH_1'),
308
- expect.stringContaining('REF_CH_1'),
309
- ])
310
- })
311
-
312
- it('resolves automatic legend orientation and supports explicit overrides', async () => {
313
- const wrapper = await mountSizedChart(
314
- {
315
- kind: 'series',
316
- series: [
317
- {
318
- id: 'first',
319
- trackId: 'shared',
320
- name: 'first',
321
- data: {
322
- kind: 'points',
323
- points: [
324
- { x: 0, y: 0 },
325
- { x: 1, y: 1 },
326
- ],
327
- },
328
- },
329
- {
330
- id: 'second',
331
- trackId: 'shared',
332
- name: 'second',
333
- data: {
334
- kind: 'points',
335
- points: [
336
- { x: 0, y: 1 },
337
- { x: 1, y: 2 },
338
- ],
339
- },
340
- },
341
- {
342
- id: 'third',
343
- trackId: 'shared',
344
- name: 'third',
345
- data: {
346
- kind: 'points',
347
- points: [
348
- { x: 0, y: 2 },
349
- { x: 1, y: 3 },
350
- ],
351
- },
352
- },
353
- ],
354
- },
355
- { grid: { rowCount: 1, columnCount: 1 } },
356
- )
357
- const positions = [
358
- 'top-left',
359
- 'top',
360
- 'top-right',
361
- 'right',
362
- 'bottom-right',
363
- 'bottom',
364
- 'bottom-left',
365
- 'left',
366
- ] as const
367
-
368
- for (const position of positions) {
369
- await wrapper.setProps({ legend: { position, orientation: 'auto' } })
370
- const legend = wrapper.get('.waveform-chart__legend')
371
- const expectedOrientation =
372
- position === 'top' || position === 'bottom' ? 'horizontal' : 'vertical'
373
- expect(legend.attributes('data-position')).toBe(position)
374
- expect(legend.attributes('data-orientation')).toBe(expectedOrientation)
375
- expect(legend.get('.waveform-legend__viewport').classes()).toContain(
376
- `waveform-legend__viewport--${position}`,
377
- )
378
- expect(
379
- legend
380
- .get('.waveform-legend__panel')
381
- .classes()
382
- .includes('waveform-legend__panel--vertical'),
383
- ).toBe(expectedOrientation === 'vertical')
384
- }
385
-
386
- await wrapper.setProps({ legend: { position: 'top', orientation: 'vertical' } })
387
- expect(wrapper.get('.waveform-chart__legend').attributes('data-orientation')).toBe('vertical')
388
- expect(wrapper.get('.waveform-legend__panel').classes()).toContain(
389
- 'waveform-legend__panel--vertical',
390
- )
391
-
392
- await wrapper.setProps({ legend: { position: 'left', orientation: 'horizontal' } })
393
- expect(wrapper.get('.waveform-chart__legend').attributes('data-orientation')).toBe('horizontal')
394
- expect(wrapper.get('.waveform-legend__panel').classes()).toContain(
395
- 'waveform-legend__panel--horizontal',
396
- )
397
-
398
- expect(wrapper.attributes('data-chart-left-margin')).toBe('80')
399
- })
400
- })
@@ -1,61 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { mountSizedChart } from '../../test/waveformChart'
4
-
5
- describe('WaveformChart multi-axis labels', () => {
6
- it('aligns single-axis and multi-axis Y-axis titles in one column', async () => {
7
- const wrapper = await mountSizedChart(
8
- {
9
- kind: 'series',
10
- series: [
11
- {
12
- id: 'single',
13
- trackId: 'single-track',
14
- name: '单轴',
15
- data: {
16
- kind: 'points',
17
- points: [
18
- { x: 0, y: -1e120 },
19
- { x: 1, y: 1e120 },
20
- ],
21
- },
22
- },
23
- {
24
- id: 'left',
25
- trackId: 'multi-track',
26
- name: '左轴',
27
- data: {
28
- kind: 'points',
29
- points: [
30
- { x: 0, y: 0 },
31
- { x: 1, y: 1 },
32
- ],
33
- },
34
- },
35
- {
36
- id: 'right',
37
- trackId: 'multi-track',
38
- name: '右轴',
39
- data: {
40
- kind: 'points',
41
- points: [
42
- { x: 0, y: 1000 },
43
- { x: 1, y: 3000 },
44
- ],
45
- },
46
- },
47
- ],
48
- },
49
- { overlayMode: 'multi-axis', grid: { rowCount: 2, columnCount: 1 } },
50
- )
51
- const tracks = wrapper.findAll('.waveform-chart__track')
52
- const titleX = (transform: string | undefined) =>
53
- Number(transform?.match(/translate\(([^,]+)/)?.[1])
54
-
55
- expect(titleX(tracks[0]!.get('.waveform-chart__y-axis-label').attributes('transform'))).toBe(
56
- titleX(
57
- tracks[1]!.findAll('.waveform-track__multi-axis-title text')[0]!.attributes('transform'),
58
- ),
59
- )
60
- })
61
- })