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,345 +0,0 @@
1
- import { flushPromises } from '@vue/test-utils'
2
- import { describe, expect, it } from 'vitest'
3
-
4
- import { type WaveformData } from '../waveform'
5
-
6
- import { gridSeries, mountSizedChart } from '../../test/waveformChart'
7
-
8
- describe('WaveformChart', () => {
9
- it('keeps clip path ids unique across chart instances', async () => {
10
- const data: WaveformData = {
11
- kind: 'series',
12
- series: [
13
- {
14
- id: 'channel-1',
15
- name: '通道 1',
16
- data: {
17
- kind: 'points',
18
- points: [
19
- { x: 0, y: 0 },
20
- { x: 1, y: 1 },
21
- ],
22
- },
23
- },
24
- ],
25
- }
26
- const first = await mountSizedChart(data)
27
- const second = await mountSizedChart(data)
28
- const firstClipPathId = first.get('clipPath').attributes('id')
29
- const secondClipPathId = second.get('clipPath').attributes('id')
30
-
31
- expect(firstClipPathId).toBeTruthy()
32
- expect(secondClipPathId).toBeTruthy()
33
- expect(firstClipPathId).not.toBe(secondClipPathId)
34
- expect(first.get('[clip-path]').attributes('clip-path')).toContain(firstClipPathId)
35
- expect(second.get('[clip-path]').attributes('clip-path')).toContain(secondClipPathId)
36
-
37
- first.unmount()
38
- second.unmount()
39
- })
40
-
41
- it('does not reuse Y scales between chart instances with the same default series ID', async () => {
42
- const first = await mountSizedChart({
43
- kind: 'points',
44
- points: [
45
- { x: 0, y: 0 },
46
- { x: 1, y: 1 },
47
- ],
48
- })
49
- const second = await mountSizedChart({
50
- kind: 'points',
51
- points: [
52
- { x: 0, y: 10_000 },
53
- { x: 1, y: 20_000 },
54
- ],
55
- })
56
-
57
- expect(first.get('.waveform-chart__axis--y').text()).not.toContain('E')
58
- expect(second.get('.waveform-chart__axis--y').text()).toContain('E+04 ')
59
- expect(second.find('.waveform-chart__axis-exponent--y').exists()).toBe(false)
60
- })
61
-
62
- it('renders a configurable zero line only when the Y domain contains zero', async () => {
63
- const wrapper = await mountSizedChart(
64
- {
65
- kind: 'points',
66
- points: [
67
- { x: 0, y: -2 },
68
- { x: 1, y: 4 },
69
- ],
70
- },
71
- { zeroLine: { visible: true, color: '#475467', width: 2, dash: '3 2' } },
72
- )
73
-
74
- const zeroLine = wrapper.get('.waveform-chart__zero-line')
75
- expect(zeroLine.attributes()).toMatchObject({
76
- stroke: '#475467',
77
- 'stroke-width': '2',
78
- 'stroke-dasharray': '3 2',
79
- 'data-y-axis-index': '0',
80
- })
81
- expect(zeroLine.attributes('y1')).toBe(zeroLine.attributes('y2'))
82
-
83
- await wrapper.setProps({ zeroLine: { visible: false } })
84
- expect(wrapper.find('.waveform-chart__zero-line').exists()).toBe(false)
85
-
86
- const positive = await mountSizedChart(
87
- {
88
- kind: 'points',
89
- points: [
90
- { x: 0, y: 2 },
91
- { x: 1, y: 4 },
92
- ],
93
- },
94
- { zeroLine: { visible: true } },
95
- )
96
- expect(positive.find('.waveform-chart__zero-line').exists()).toBe(false)
97
- })
98
-
99
- it('renders zero lines from each visible Y axis in multi-axis mode', async () => {
100
- const wrapper = await mountSizedChart(
101
- {
102
- kind: 'series',
103
- series: [
104
- {
105
- id: 'small',
106
- trackId: 'overlay',
107
- name: 'small',
108
- data: {
109
- kind: 'points',
110
- points: [
111
- { x: 0, y: -1 },
112
- { x: 1, y: 3 },
113
- ],
114
- },
115
- },
116
- {
117
- id: 'large',
118
- trackId: 'overlay',
119
- name: 'large',
120
- data: {
121
- kind: 'points',
122
- points: [
123
- { x: 0, y: -10 },
124
- { x: 1, y: 2 },
125
- ],
126
- },
127
- },
128
- ],
129
- },
130
- { overlayMode: 'multi-axis', zeroLine: { visible: true } },
131
- )
132
-
133
- const zeroLines = wrapper.findAll('.waveform-chart__zero-line')
134
- expect(zeroLines).toHaveLength(2)
135
- expect(zeroLines.map((line) => line.attributes('data-y-axis-index'))).toEqual(['0', '1'])
136
- expect(zeroLines[0].attributes('y1')).not.toBe(zeroLines[1].attributes('y1'))
137
- })
138
-
139
- it('hides X and Y axis lines independently while preserving axis text and the frame', async () => {
140
- const wrapper = await mountSizedChart({
141
- kind: 'series',
142
- series: [
143
- {
144
- id: 'channel',
145
- name: 'Voltage',
146
- data: {
147
- kind: 'points',
148
- points: [
149
- { x: 0, y: -1 },
150
- { x: 10_000, y: 1 },
151
- ],
152
- },
153
- },
154
- ],
155
- })
156
- const xAxis = wrapper.get('.waveform-chart__axis--x')
157
- const yAxis = wrapper.get('.waveform-chart__axis--y')
158
-
159
- expect(xAxis.classes()).not.toContain('waveform-track__axis--line-hidden')
160
- expect(yAxis.classes()).not.toContain('waveform-track__axis--line-hidden')
161
-
162
- await wrapper.setProps({ axes: { x: { lineVisible: false } } })
163
- await flushPromises()
164
- expect(xAxis.classes()).toContain('waveform-track__axis--line-hidden')
165
- expect(yAxis.classes()).not.toContain('waveform-track__axis--line-hidden')
166
- expect(xAxis.get('path.domain').attributes('display')).toBe('none')
167
- expect(
168
- xAxis.findAll('.tick line').every((line) => line.attributes('display') === undefined),
169
- ).toBe(true)
170
- expect(yAxis.get('path.domain').attributes('display')).toBeUndefined()
171
-
172
- await wrapper.setProps({
173
- axes: {
174
- x: { lineVisible: false },
175
- y: { lineVisible: false },
176
- },
177
- grid: {
178
- rowCount: 1,
179
- columnCount: 1,
180
- trackLines: { channel: { horizontal: false, vertical: false } },
181
- },
182
- frameStyle: { borderColor: '#dc2626', borderWidth: 2 },
183
- })
184
- await flushPromises()
185
-
186
- expect(xAxis.classes()).toContain('waveform-track__axis--line-hidden')
187
- expect(yAxis.classes()).toContain('waveform-track__axis--line-hidden')
188
- expect(yAxis.get('path.domain').attributes('display')).toBe('none')
189
- expect(
190
- yAxis.findAll('.tick line').every((line) => line.attributes('display') === undefined),
191
- ).toBe(true)
192
- expect(xAxis.findAll('text').length).toBeGreaterThan(0)
193
- expect(yAxis.findAll('text').length).toBeGreaterThan(0)
194
- expect(wrapper.findAll('.waveform-chart__axis-endpoint')).toHaveLength(2)
195
- expect(wrapper.get('.waveform-chart__y-axis-label').text()).toBe('Voltage')
196
- expect(wrapper.findAll('[data-grid-direction]')).toHaveLength(0)
197
- expect(wrapper.get('.waveform-chart__plot-frame').attributes()).toMatchObject({
198
- stroke: '#dc2626',
199
- 'stroke-width': '2',
200
- })
201
-
202
- await wrapper.setProps({ axes: { x: { lineVisible: true }, y: { lineVisible: true } } })
203
- await flushPromises()
204
- expect(xAxis.get('path.domain').attributes('display')).toBeUndefined()
205
- expect(yAxis.get('path.domain').attributes('display')).toBeUndefined()
206
- })
207
-
208
- it('preserves a titled multi-axis plot and hides auxiliary layers in clean view', async () => {
209
- const data: WaveformData = {
210
- kind: 'series',
211
- series: [
212
- {
213
- id: 'first',
214
- trackId: 'overlay',
215
- name: 'first',
216
- data: {
217
- kind: 'points',
218
- points: [
219
- { x: 0, y: -1 },
220
- { x: 1, y: 1 },
221
- ],
222
- },
223
- },
224
- {
225
- id: 'second',
226
- trackId: 'overlay',
227
- name: 'second',
228
- data: {
229
- kind: 'points',
230
- points: [
231
- { x: 0, y: 10_000 },
232
- { x: 10_000, y: 20_000 },
233
- ],
234
- },
235
- },
236
- {
237
- id: 'third',
238
- name: 'third',
239
- data: {
240
- kind: 'points',
241
- points: [
242
- { x: 0, y: 2 },
243
- { x: 10_000, y: 3 },
244
- ],
245
- },
246
- },
247
- ],
248
- }
249
- const sharedProps = {
250
- grid: { rowCount: 1, columnCount: 1, showPagination: true },
251
- overlayMode: 'multi-axis' as const,
252
- frameNumber: 1,
253
- annotations: [{ id: 'note', seriesId: 'first', x: 0.5, y: 0, text: 'hidden note' }],
254
- zeroLine: { visible: true },
255
- title: { text: 'hidden title' },
256
- axes: { x: { lineVisible: false }, y: { lineVisible: false } },
257
- frameStyle: { borderColor: '#dc2626', borderWidth: 2, borderStyle: 'dashed' as const },
258
- }
259
- const regularWrapper = await mountSizedChart(data, sharedProps)
260
- const wrapper = await mountSizedChart(data, {
261
- ...sharedProps,
262
- cleanView: true,
263
- })
264
-
265
- const regularTrack = regularWrapper.get('.waveform-chart__track')
266
- const cleanTrack = wrapper.get('.waveform-chart__track')
267
- const geometryAttributes = [
268
- 'data-track-left',
269
- 'data-track-top',
270
- 'data-track-width',
271
- 'data-track-height',
272
- ]
273
-
274
- expect(wrapper.get('.waveform-chart').attributes('data-chart-left-margin')).toBe(
275
- regularWrapper.get('.waveform-chart').attributes('data-chart-left-margin'),
276
- )
277
- expect(wrapper.get('.waveform-chart').attributes('data-title-area-height')).toBe(
278
- regularWrapper.get('.waveform-chart').attributes('data-title-area-height'),
279
- )
280
- geometryAttributes.forEach((attribute) => {
281
- expect(cleanTrack.attributes(attribute)).toBe(regularTrack.attributes(attribute))
282
- })
283
- expect(wrapper.get('.waveform-chart').classes()).toContain('waveform-chart--clean')
284
- expect(getComputedStyle(wrapper.get('.waveform-chart').element).borderColor).toBe(
285
- 'rgba(0, 0, 0, 0)',
286
- )
287
- expect(wrapper.findAll('.waveform-chart__series')).toHaveLength(2)
288
- expect(wrapper.find('.waveform-chart__overlay--independent').exists()).toBe(true)
289
- expect(wrapper.get('.waveform-chart__title-area').attributes('aria-hidden')).toBe('true')
290
- expect(wrapper.find('.waveform-chart__title-visual').exists()).toBe(false)
291
- const xAxis = wrapper.get('.waveform-chart__axis--x')
292
- const yAxes = wrapper.findAll('.waveform-chart__axis--y')
293
- expect(yAxes).toHaveLength(2)
294
- expect(xAxis.findAll('.tick line').length).toBeGreaterThan(0)
295
- expect(xAxis.findAll('.tick text').length).toBeGreaterThan(0)
296
- yAxes.forEach((axis) => {
297
- expect(axis.findAll('.tick line').length).toBeGreaterThan(0)
298
- expect(axis.findAll('.tick text').length).toBeGreaterThan(0)
299
- expect(axis.get('path.domain').attributes('display')).toBe('none')
300
- })
301
- expect(xAxis.get('path.domain').attributes('display')).toBe('none')
302
- expect(wrapper.findAll('.waveform-chart__axis-endpoint')).toHaveLength(2)
303
- expect(wrapper.find('.waveform-chart__axis-exponent--x').exists()).toBe(false)
304
- expect(yAxes.some((axis) => axis.text().includes('E+04 '))).toBe(true)
305
- expect(wrapper.find('.waveform-chart__axis-exponent--y').exists()).toBe(false)
306
- expect(wrapper.find('.waveform-chart__grid').exists()).toBe(false)
307
- expect(wrapper.get('.waveform-chart__plot-frame').attributes()).toMatchObject({
308
- stroke: '#dc2626',
309
- 'stroke-width': '2',
310
- 'stroke-dasharray': '6 4',
311
- })
312
- expect(wrapper.find('.waveform-chart__plot-background').exists()).toBe(false)
313
- expect(wrapper.find('.waveform-chart__watermark').exists()).toBe(false)
314
- expect(wrapper.find('.waveform-chart__legend-layer').exists()).toBe(false)
315
- expect(wrapper.find('.waveform-chart__label').exists()).toBe(false)
316
- expect(wrapper.find('.waveform-chart__y-axis-label').exists()).toBe(false)
317
- expect(wrapper.find('.waveform-chart__zero-line').exists()).toBe(false)
318
- expect(wrapper.find('.waveform-annotation-layer').exists()).toBe(false)
319
- expect(wrapper.find('.ant-pagination').exists()).toBe(false)
320
- })
321
-
322
- it('preserves every track geometry in a multi-column clean view', async () => {
323
- const props = {
324
- displayMode: 'independent' as const,
325
- grid: { rowCount: 2, columnCount: 2 },
326
- }
327
- const regularWrapper = await mountSizedChart(gridSeries(4), props)
328
- const cleanWrapper = await mountSizedChart(gridSeries(4), { ...props, cleanView: true })
329
- const geometryAttributes = [
330
- 'data-track-left',
331
- 'data-track-top',
332
- 'data-track-width',
333
- 'data-track-height',
334
- ]
335
- const regularTracks = regularWrapper.findAll('.waveform-chart__track')
336
- const cleanTracks = cleanWrapper.findAll('.waveform-chart__track')
337
-
338
- expect(cleanTracks).toHaveLength(regularTracks.length)
339
- cleanTracks.forEach((track, index) => {
340
- geometryAttributes.forEach((attribute) => {
341
- expect(track.attributes(attribute)).toBe(regularTracks[index].attributes(attribute))
342
- })
343
- })
344
- })
345
- })
@@ -1,327 +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 { mountSizedChart } from '../../test/waveformChart'
6
- import type { WaveformData, WaveformDisplayMode } from '../data/types'
7
-
8
- function annotationEditorExists() {
9
- return Boolean(
10
- Array.from(document.body.querySelectorAll<HTMLElement>('[role="dialog"]'))
11
- .filter((element) => element.closest('.waveform-annotation-editor'))
12
- .at(-1),
13
- )
14
- }
15
-
16
- const presentationData: WaveformData = {
17
- kind: 'series',
18
- series: [
19
- {
20
- id: 'low',
21
- trackId: 'shared',
22
- name: '低量程',
23
- data: {
24
- kind: 'points',
25
- points: [
26
- { x: 0, y: 0 },
27
- { x: 1, y: 10 },
28
- { x: 2, y: 5 },
29
- ],
30
- },
31
- },
32
- {
33
- id: 'high',
34
- trackId: 'shared',
35
- name: '高量程',
36
- data: {
37
- kind: 'points',
38
- points: [
39
- { x: 0, y: 100 },
40
- { x: 1, y: 200 },
41
- { x: 2, y: 150 },
42
- ],
43
- },
44
- },
45
- {
46
- id: 'mid',
47
- trackId: 'shared',
48
- name: '中量程',
49
- data: {
50
- kind: 'points',
51
- points: [
52
- { x: 0, y: 50 },
53
- { x: 1, y: 100 },
54
- { x: 2, y: 75 },
55
- ],
56
- },
57
- },
58
- {
59
- id: 'other',
60
- name: '其他通道',
61
- data: {
62
- kind: 'points',
63
- points: [
64
- { x: 0, y: -1 },
65
- { x: 1, y: 1 },
66
- { x: 2, y: 0 },
67
- ],
68
- },
69
- },
70
- ],
71
- }
72
-
73
- function setOverlayBounds(overlay: ReturnType<Awaited<ReturnType<typeof mountSizedChart>>['get']>) {
74
- const width = Number(overlay.attributes('width'))
75
- const height = Number(overlay.attributes('height'))
76
- Object.defineProperty(overlay.element, 'getBoundingClientRect', {
77
- value: () => ({ left: 0, top: 0, width, height }),
78
- })
79
- return { width, height }
80
- }
81
-
82
- function dispatchPointer(
83
- element: Element,
84
- type: string,
85
- options: MouseEventInit & { pointerId: number },
86
- ) {
87
- const event = new MouseEvent(type, { bubbles: true, cancelable: true, ...options })
88
- Object.defineProperty(event, 'pointerId', { value: options.pointerId })
89
- element.dispatchEvent(event)
90
- }
91
-
92
- describe('WaveformChart presentation mode', () => {
93
- it('keeps existing plot interaction enabled by default', async () => {
94
- const wrapper = await mountSizedChart(presentationData, {
95
- grid: { rowCount: 1, columnCount: 1 },
96
- })
97
- const overlay = wrapper.get('.waveform-chart__overlay--independent')
98
- const { width, height } = setOverlayBounds(overlay)
99
-
100
- expect(wrapper.attributes('data-presentation-mode')).toBe('false')
101
- expect(overlay.classes()).toContain('is-zoomable')
102
-
103
- overlay.element.dispatchEvent(
104
- new MouseEvent('pointermove', {
105
- clientX: width / 2,
106
- clientY: height / 2,
107
- bubbles: true,
108
- }),
109
- )
110
- flushAnimationFrames()
111
- await flushPromises()
112
-
113
- expect(wrapper.find('.waveform-chart__tooltip').exists()).toBe(true)
114
- expect(wrapper.emitted('point-hover')?.length).toBeGreaterThan(0)
115
- })
116
-
117
- it.each<WaveformDisplayMode>(['independent', 'separated'])(
118
- 'blocks plot mouse events in %s layout',
119
- async (displayMode) => {
120
- const wrapper = await mountSizedChart(presentationData, {
121
- annotations: [{ id: 'note', seriesId: 'low', x: 1, y: 10, text: '只读标注' }],
122
- displayMode,
123
- grid: { rowCount: 1, columnCount: 1 },
124
- interactionMode: 'annotation',
125
- presentationMode: true,
126
- })
127
- const overlay = wrapper.get('.waveform-chart__overlay')
128
- const { width, height } = setOverlayBounds(overlay)
129
-
130
- expect(wrapper.attributes('data-presentation-mode')).toBe('true')
131
- expect(overlay.classes()).not.toContain('is-zoomable')
132
- expect(overlay.classes()).not.toContain('is-annotating')
133
-
134
- overlay.element.dispatchEvent(
135
- new MouseEvent('pointermove', {
136
- clientX: width / 2,
137
- clientY: height / 2,
138
- bubbles: true,
139
- }),
140
- )
141
- overlay.element.dispatchEvent(
142
- new WheelEvent('wheel', {
143
- deltaY: -4000,
144
- clientX: width / 2,
145
- clientY: height / 2,
146
- bubbles: true,
147
- cancelable: true,
148
- }),
149
- )
150
- overlay.element.dispatchEvent(
151
- new MouseEvent('click', {
152
- clientX: width / 2,
153
- clientY: height / 2,
154
- bubbles: true,
155
- cancelable: true,
156
- }),
157
- )
158
- overlay.element.dispatchEvent(
159
- new MouseEvent('contextmenu', {
160
- clientX: width / 2,
161
- clientY: height / 2,
162
- bubbles: true,
163
- cancelable: true,
164
- }),
165
- )
166
- wrapper
167
- .get('.waveform-chart__svg')
168
- .element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }))
169
- await wrapper.get('[data-annotation-id="note"]').trigger('contextmenu', {
170
- clientX: width / 2,
171
- clientY: height / 2,
172
- })
173
- const annotation = wrapper.get('[data-annotation-id="note"]').element
174
- dispatchPointer(annotation, 'pointerdown', {
175
- button: 0,
176
- clientX: width / 2,
177
- clientY: height / 2,
178
- pointerId: 42,
179
- })
180
- dispatchPointer(annotation, 'pointermove', {
181
- clientX: width / 2 + 30,
182
- clientY: height / 2 + 20,
183
- pointerId: 42,
184
- })
185
- dispatchPointer(annotation, 'pointerup', {
186
- clientX: width / 2 + 30,
187
- clientY: height / 2 + 20,
188
- pointerId: 42,
189
- })
190
- flushAnimationFrames()
191
- await flushPromises()
192
-
193
- expect(wrapper.find('.waveform-chart__tooltip').exists()).toBe(false)
194
- expect(wrapper.find('.waveform-annotation-editor').exists()).toBe(false)
195
- expect(wrapper.find('.waveform-annotation-context-menu').exists()).toBe(false)
196
- expect(wrapper.emitted('point-hover')).toBeUndefined()
197
- expect(wrapper.emitted('zoom-change')).toBeUndefined()
198
- expect(wrapper.emitted('zoom-end')).toBeUndefined()
199
- expect(wrapper.emitted('zoom-reset')).toBeUndefined()
200
- expect(wrapper.emitted('update:annotations')).toBeUndefined()
201
- },
202
- )
203
-
204
- it('keeps the legend and pagination interactive', async () => {
205
- const wrapper = await mountSizedChart(presentationData, {
206
- grid: { rowCount: 1, columnCount: 1, showPagination: true },
207
- legend: { interactive: true },
208
- presentationMode: true,
209
- })
210
-
211
- await wrapper.findAll('.waveform-chart__legend-item')[1]!.trigger('click')
212
- await flushPromises()
213
- expect(wrapper.emitted('update:hidden-series-ids')?.at(-1)).toEqual([['high']])
214
-
215
- await wrapper.get('.ant-pagination-next button').trigger('click')
216
- await flushPromises()
217
- expect(wrapper.emitted('page-change')?.at(-1)).toEqual([2, 2])
218
- })
219
-
220
- it('cleans active UI state and restores interaction without resetting the viewport', async () => {
221
- const wrapper = await mountSizedChart(presentationData, {
222
- grid: { rowCount: 1, columnCount: 1 },
223
- })
224
- const overlay = wrapper.get('.waveform-chart__overlay--independent')
225
- const { width, height } = setOverlayBounds(overlay)
226
-
227
- overlay.element.dispatchEvent(
228
- new WheelEvent('wheel', {
229
- deltaY: -4000,
230
- clientX: width / 2,
231
- clientY: height / 2,
232
- bubbles: true,
233
- cancelable: true,
234
- }),
235
- )
236
- flushAnimationFrames()
237
- await flushPromises()
238
- const zoomedEndpoint = wrapper.get('.waveform-chart__axis-endpoint--end').text()
239
-
240
- dispatchPointer(overlay.element, 'pointerdown', {
241
- button: 0,
242
- clientX: width * 0.25,
243
- clientY: height / 2,
244
- pointerId: 41,
245
- })
246
- dispatchPointer(overlay.element, 'pointermove', {
247
- clientX: width * 0.75,
248
- clientY: height / 2,
249
- pointerId: 41,
250
- })
251
- await flushPromises()
252
- expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(true)
253
-
254
- await wrapper.setProps({ presentationMode: true })
255
- await flushPromises()
256
-
257
- expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(false)
258
- expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe(zoomedEndpoint)
259
-
260
- const zoomEventCount = wrapper.emitted('zoom-change')?.length ?? 0
261
- await wrapper.setProps({ presentationMode: false })
262
- await flushPromises()
263
- overlay.element.dispatchEvent(
264
- new WheelEvent('wheel', {
265
- deltaY: 200,
266
- clientX: width / 2,
267
- clientY: height / 2,
268
- bubbles: true,
269
- cancelable: true,
270
- }),
271
- )
272
- flushAnimationFrames()
273
- await flushPromises()
274
-
275
- expect(wrapper.emitted('zoom-change')?.length).toBeGreaterThan(zoomEventCount)
276
- })
277
-
278
- it('closes hover and annotation UI when enabled at runtime', async () => {
279
- const wrapper = await mountSizedChart(presentationData, {
280
- grid: { rowCount: 1, columnCount: 1 },
281
- interactionMode: 'annotation',
282
- })
283
- const overlay = wrapper.get('.waveform-chart__overlay--independent')
284
- const { width, height } = setOverlayBounds(overlay)
285
-
286
- overlay.element.dispatchEvent(
287
- new MouseEvent('pointermove', {
288
- clientX: width / 2,
289
- clientY: height / 2,
290
- bubbles: true,
291
- }),
292
- )
293
- flushAnimationFrames()
294
- await flushPromises()
295
- expect(wrapper.find('.waveform-chart__tooltip').exists()).toBe(true)
296
-
297
- overlay.element.dispatchEvent(
298
- new MouseEvent('contextmenu', {
299
- clientX: width / 2,
300
- clientY: height / 2,
301
- bubbles: true,
302
- cancelable: true,
303
- }),
304
- )
305
- await flushPromises()
306
- expect(annotationEditorExists()).toBe(true)
307
-
308
- await wrapper.setProps({ presentationMode: true })
309
- await flushPromises()
310
-
311
- expect(wrapper.find('.waveform-chart__tooltip').exists()).toBe(false)
312
- expect(annotationEditorExists()).toBe(false)
313
- expect(wrapper.emitted('point-hover')?.at(-1)).toEqual([null])
314
-
315
- await wrapper.setProps({ presentationMode: false })
316
- overlay.element.dispatchEvent(
317
- new MouseEvent('pointermove', {
318
- clientX: width / 2,
319
- clientY: height / 2,
320
- bubbles: true,
321
- }),
322
- )
323
- flushAnimationFrames()
324
- await flushPromises()
325
- expect(wrapper.find('.waveform-chart__tooltip').exists()).toBe(true)
326
- })
327
- })