waveform-analysis 0.1.63 → 0.1.65
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 +21 -5
- package/dist/index.cjs +1 -1
- package/dist/index.js +986 -964
- package/dist/style.css +1 -1
- package/dist/types/components/core/constants.d.ts +1 -1
- package/dist/types/components/core/trackLayoutBuilder.d.ts +1 -0
- package/dist/types/components/core/yAxisConstants.d.ts +1 -1
- package/dist/types/types/chart.d.ts +6 -1
- package/package.json +1 -1
- package/src/App.vue +2 -2
- package/src/components/WaveformChart.css +4 -0
- package/src/components/WaveformChart.vue +2 -2
- package/src/components/core/constants.ts +3 -3
- package/src/components/core/layout.ts +1 -1
- package/src/components/core/trackLayoutBuilder.ts +42 -1
- package/src/components/core/useWaveformLayout.ts +2 -1
- package/src/components/core/useWaveformPresentation.ts +1 -1
- package/src/components/core/xDomain.ts +26 -2
- package/src/components/core/yAxisConstants.ts +1 -1
- package/src/components/rendering/WaveformLegend.vue +1 -1
- package/src/components/rendering/WaveformSeriesLayer.vue +1 -1
- package/src/components/rendering/WaveformTrack.css +5 -2
- package/src/components/rendering/WaveformTrack.vue +7 -1
- package/src/components/rendering/WaveformTrackAxes.vue +8 -2
- package/src/demo/DemoChartHost.vue +1 -0
- package/src/types/chart.ts +6 -1
- package/src/App.test.ts +0 -400
- package/src/components/annotation/components.test.ts +0 -372
- package/src/components/annotation/markup.test.ts +0 -371
- package/src/components/annotation/serialization.test.ts +0 -114
- package/src/components/core/constants.test.ts +0 -29
- package/src/components/core/fixedYDomainLayout.test.ts +0 -204
- package/src/components/core/grid.test.ts +0 -197
- package/src/components/core/latestTaskScheduler.test.ts +0 -51
- package/src/components/core/layout.test.ts +0 -373
- package/src/components/core/title.test.ts +0 -76
- package/src/components/core/useWaveformData.test.ts +0 -95
- package/src/components/core/useWaveformRenderSampling.test.ts +0 -17
- package/src/components/core/xDomain.test.ts +0 -28
- package/src/components/core/yAxisNice.test.ts +0 -174
- package/src/components/core/yAxisSlotLayout.test.ts +0 -165
- package/src/components/core/yDomain.test.ts +0 -56
- package/src/components/interaction/WaveformTooltip.test.ts +0 -276
- package/src/components/interaction/viewportInteractionState.test.ts +0 -101
- package/src/components/utils/useAnimationFrameThrottle.test.ts +0 -53
- package/src/components/waveformChartCases/annotationEditingAndReprojection.test.ts +0 -257
- package/src/components/waveformChartCases/compactAndSharedHover.test.ts +0 -358
- package/src/components/waveformChartCases/dataAndHoverPerformance.test.ts +0 -358
- package/src/components/waveformChartCases/dataLifecycle.test.ts +0 -310
- package/src/components/waveformChartCases/frameGridAndFormatting.test.ts +0 -389
- package/src/components/waveformChartCases/gridFill.test.ts +0 -95
- package/src/components/waveformChartCases/incompleteDataHover.test.ts +0 -155
- package/src/components/waveformChartCases/interactionAndAnnotationCreation.test.ts +0 -328
- package/src/components/waveformChartCases/layoutAndDomains.test.ts +0 -371
- package/src/components/waveformChartCases/legendVisibility.test.ts +0 -350
- package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +0 -400
- package/src/components/waveformChartCases/multiAxisLabelAlignment.test.ts +0 -61
- package/src/components/waveformChartCases/presentationAndAxes.test.ts +0 -345
- package/src/components/waveformChartCases/presentationMode.test.ts +0 -327
- package/src/components/waveformChartCases/renderingStyles.test.ts +0 -283
- package/src/components/waveformChartCases/sizingAndTitles.test.ts +0 -370
- package/src/components/waveformChartCases/trackOrder.test.ts +0 -323
- package/src/components/waveformChartCases/viewportBoxAndPan.test.ts +0 -365
- package/src/components/waveformChartCases/viewportConstraintsAndReset.test.ts +0 -311
- package/src/components/waveformChartCases/viewportLifecycle.test.ts +0 -132
- package/src/components/waveformChartCases/viewportReset.test.ts +0 -251
- package/src/components/waveformChartCases/wheelZoomOut.test.ts +0 -114
- package/src/components/waveformChartCases/workerSamplingIntegration.test.ts +0 -117
- package/src/components/waveformChartCases/xDomainStrategy.test.ts +0 -168
- package/src/components/waveformChartCases/yAxisLayout.test.ts +0 -103
- package/src/components/waveformChartCases/zoomIntentAndDataRebind.test.ts +0 -213
- package/src/components/waveformChartCases/zoomPointConstraints.test.ts +0 -308
- package/src/components/waveformLegendGeometry.test.ts +0 -21
- package/src/components/waveformNormalization.test.ts +0 -170
- package/src/core/data.test.ts +0 -241
- package/src/core/rendering.test.ts +0 -267
- package/src/core/renderingStrategies.test.ts +0 -90
- package/src/core/samplingReference.test.ts +0 -124
- package/src/core/wasmSampling.test.ts +0 -205
- package/src/core/workerSampling/multiresolution.test.ts +0 -69
- package/src/core/workerSampling/protocol.test.ts +0 -34
- package/src/core/workerSampling/repository.test.ts +0 -400
- package/src/core/workerSampling/repositoryCache.test.ts +0 -163
- package/src/core/workerSampling/repositorySampling.test.ts +0 -106
- package/src/core/workerSampling/repositoryTypedDataset.test.ts +0 -89
- package/src/core/workerSampling/repositoryWasmDataset.test.ts +0 -70
- package/src/data/simulatedWaveforms.test.ts +0 -60
- package/src/demo/plotMarginControls.test.ts +0 -29
- package/src/demo/xAxisLabelControls.test.ts +0 -86
- package/src/test/setup.ts +0 -82
- package/src/test/waveformChart.ts +0 -75
- package/src/utils/domain.test.ts +0 -28
- package/src/utils/formatters.test.ts +0 -131
- package/src/utils/sampling.test.ts +0 -226
- package/src/views/FixedYDomainDemo.test.ts +0 -44
- package/src/views/WasmSamplingDemo.test.ts +0 -13
- package/src/views/wasmSamplingDemoSampling.test.ts +0 -27
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { flushPromises } from '@vue/test-utils'
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { flushAnimationFrames } from '../../test/setup'
|
|
5
|
-
|
|
6
|
-
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
|
7
|
-
|
|
8
|
-
describe('WaveformChart', () => {
|
|
9
|
-
it('does not zoom a track when its visible sample count is below the configured minimum', async () => {
|
|
10
|
-
const wrapper = await mountSizedChart(
|
|
11
|
-
{
|
|
12
|
-
kind: 'points',
|
|
13
|
-
points: [
|
|
14
|
-
{ x: 0, y: 0 },
|
|
15
|
-
{ x: 1, y: 10 },
|
|
16
|
-
{ x: 2, y: 20 },
|
|
17
|
-
],
|
|
18
|
-
},
|
|
19
|
-
{ minVisiblePoints: 10 },
|
|
20
|
-
)
|
|
21
|
-
const overlay = wrapper.get('.waveform-chart__overlay--independent')
|
|
22
|
-
const width = Number(overlay.attributes('width'))
|
|
23
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
24
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
25
|
-
})
|
|
26
|
-
overlay.element.dispatchEvent(
|
|
27
|
-
new WheelEvent('wheel', {
|
|
28
|
-
deltaY: -1000,
|
|
29
|
-
clientX: width / 2,
|
|
30
|
-
clientY: 145,
|
|
31
|
-
bubbles: true,
|
|
32
|
-
cancelable: true,
|
|
33
|
-
}),
|
|
34
|
-
)
|
|
35
|
-
flushAnimationFrames()
|
|
36
|
-
await flushPromises()
|
|
37
|
-
|
|
38
|
-
expect(wrapper.emitted('zoom-change')).toBeUndefined()
|
|
39
|
-
expect(wrapper.emitted('zoom-end')).toBeUndefined()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('ignores shared viewport dragging', async () => {
|
|
43
|
-
const wrapper = await mountSizedChart({
|
|
44
|
-
kind: 'points',
|
|
45
|
-
points: [
|
|
46
|
-
{ x: 0, y: 0 },
|
|
47
|
-
{ x: 2, y: 1 },
|
|
48
|
-
],
|
|
49
|
-
})
|
|
50
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
51
|
-
const width = Number(overlay.attributes('width'))
|
|
52
|
-
const createDragEvent = (type: string, init: MouseEventInit) => {
|
|
53
|
-
const event = new MouseEvent(type, init)
|
|
54
|
-
Object.defineProperty(event, 'view', { value: window })
|
|
55
|
-
return event
|
|
56
|
-
}
|
|
57
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
58
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
59
|
-
})
|
|
60
|
-
overlay.element.dispatchEvent(
|
|
61
|
-
createDragEvent('mousedown', {
|
|
62
|
-
button: 0,
|
|
63
|
-
clientX: width / 2,
|
|
64
|
-
clientY: 145,
|
|
65
|
-
bubbles: true,
|
|
66
|
-
cancelable: true,
|
|
67
|
-
}),
|
|
68
|
-
)
|
|
69
|
-
window.dispatchEvent(
|
|
70
|
-
new MouseEvent('mousemove', {
|
|
71
|
-
clientX: width / 2 + 80,
|
|
72
|
-
clientY: 145,
|
|
73
|
-
bubbles: true,
|
|
74
|
-
}),
|
|
75
|
-
)
|
|
76
|
-
window.dispatchEvent(createDragEvent('mouseup', { bubbles: true }))
|
|
77
|
-
flushAnimationFrames()
|
|
78
|
-
await flushPromises()
|
|
79
|
-
|
|
80
|
-
expect(wrapper.emitted('zoom-change')).toBeUndefined()
|
|
81
|
-
expect(wrapper.emitted('zoom-end')).toBeUndefined()
|
|
82
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
83
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('2000')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('ignores independent viewport dragging', async () => {
|
|
87
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
88
|
-
displayMode: 'independent',
|
|
89
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
90
|
-
})
|
|
91
|
-
const overlay = wrapper.findAll('.waveform-chart__overlay--independent')[0]
|
|
92
|
-
const width = Number(overlay.attributes('width'))
|
|
93
|
-
const createDragEvent = (type: string, init: MouseEventInit) => {
|
|
94
|
-
const event = new MouseEvent(type, init)
|
|
95
|
-
Object.defineProperty(event, 'view', { value: window })
|
|
96
|
-
return event
|
|
97
|
-
}
|
|
98
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
99
|
-
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
overlay.element.dispatchEvent(
|
|
103
|
-
createDragEvent('mousedown', {
|
|
104
|
-
button: 0,
|
|
105
|
-
clientX: width / 2,
|
|
106
|
-
clientY: 130,
|
|
107
|
-
bubbles: true,
|
|
108
|
-
cancelable: true,
|
|
109
|
-
}),
|
|
110
|
-
)
|
|
111
|
-
window.dispatchEvent(
|
|
112
|
-
new MouseEvent('mousemove', {
|
|
113
|
-
clientX: width / 2 + 60,
|
|
114
|
-
clientY: 130,
|
|
115
|
-
bubbles: true,
|
|
116
|
-
}),
|
|
117
|
-
)
|
|
118
|
-
window.dispatchEvent(createDragEvent('mouseup', { bubbles: true }))
|
|
119
|
-
flushAnimationFrames()
|
|
120
|
-
await flushPromises()
|
|
121
|
-
|
|
122
|
-
expect(wrapper.emitted('zoom-change')).toBeUndefined()
|
|
123
|
-
expect(wrapper.emitted('zoom-end')).toBeUndefined()
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
it('includes track and series IDs in independent zoom-end payloads', async () => {
|
|
127
|
-
vi.useFakeTimers()
|
|
128
|
-
try {
|
|
129
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
130
|
-
displayMode: 'independent',
|
|
131
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
132
|
-
})
|
|
133
|
-
const overlay = wrapper.findAll('.waveform-chart__overlay--independent')[0]
|
|
134
|
-
const overlayWidth = Number(overlay.attributes('width'))
|
|
135
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
136
|
-
value: () => ({ left: 0, top: 0, width: overlayWidth, height: 260 }),
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
overlay.element.dispatchEvent(
|
|
140
|
-
new WheelEvent('wheel', {
|
|
141
|
-
deltaY: -4000,
|
|
142
|
-
clientX: overlayWidth / 2,
|
|
143
|
-
clientY: 130,
|
|
144
|
-
bubbles: true,
|
|
145
|
-
cancelable: true,
|
|
146
|
-
}),
|
|
147
|
-
)
|
|
148
|
-
flushAnimationFrames()
|
|
149
|
-
await vi.advanceTimersByTimeAsync(200)
|
|
150
|
-
await flushPromises()
|
|
151
|
-
|
|
152
|
-
const payload = wrapper.emitted('zoom-end')?.at(-1)?.[0] as
|
|
153
|
-
{ trackIndex: number; seriesIds: string[] } | undefined
|
|
154
|
-
expect(payload).toMatchObject({ trackIndex: 0, seriesIds: ['channel-0'] })
|
|
155
|
-
} finally {
|
|
156
|
-
vi.useRealTimers()
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('keeps the global minimum zoom span after replacing the data window', async () => {
|
|
161
|
-
const wrapper = await mountSizedChart(
|
|
162
|
-
{
|
|
163
|
-
kind: 'points',
|
|
164
|
-
points: [
|
|
165
|
-
{ x: 0, y: 0 },
|
|
166
|
-
{ x: 100, y: 1 },
|
|
167
|
-
],
|
|
168
|
-
},
|
|
169
|
-
{ minZoomSpan: 10 },
|
|
170
|
-
)
|
|
171
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
172
|
-
const width = Number(overlay.attributes('width'))
|
|
173
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
174
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
175
|
-
})
|
|
176
|
-
const zoomAtCenter = async () => {
|
|
177
|
-
overlay.element.dispatchEvent(
|
|
178
|
-
new WheelEvent('wheel', {
|
|
179
|
-
deltaY: -4000,
|
|
180
|
-
clientX: width / 2,
|
|
181
|
-
clientY: 145,
|
|
182
|
-
bubbles: true,
|
|
183
|
-
cancelable: true,
|
|
184
|
-
}),
|
|
185
|
-
)
|
|
186
|
-
flushAnimationFrames()
|
|
187
|
-
await flushPromises()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
await zoomAtCenter()
|
|
191
|
-
const firstDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
192
|
-
expect(firstDomain[1] - firstDomain[0]).toBeCloseTo(10)
|
|
193
|
-
|
|
194
|
-
await wrapper.setProps({
|
|
195
|
-
data: {
|
|
196
|
-
kind: 'points',
|
|
197
|
-
points: [
|
|
198
|
-
{ x: firstDomain[0], y: 0 },
|
|
199
|
-
{ x: firstDomain[1], y: 1 },
|
|
200
|
-
],
|
|
201
|
-
},
|
|
202
|
-
})
|
|
203
|
-
await flushPromises()
|
|
204
|
-
await zoomAtCenter()
|
|
205
|
-
|
|
206
|
-
const secondDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
207
|
-
expect(secondDomain[1] - secondDomain[0]).toBeCloseTo(10)
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('zooms a shared viewport back out after loading a narrower data window', async () => {
|
|
211
|
-
const wrapper = await mountSizedChart(
|
|
212
|
-
{
|
|
213
|
-
kind: 'points',
|
|
214
|
-
points: [
|
|
215
|
-
{ x: 0, y: 0 },
|
|
216
|
-
{ x: 100, y: 1 },
|
|
217
|
-
],
|
|
218
|
-
},
|
|
219
|
-
{ displayMode: 'separated', initialXDomain: [0, 100] },
|
|
220
|
-
)
|
|
221
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
222
|
-
const width = Number(overlay.attributes('width'))
|
|
223
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
224
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
225
|
-
})
|
|
226
|
-
const dispatchWheel = async (deltaY: number) => {
|
|
227
|
-
overlay.element.dispatchEvent(
|
|
228
|
-
new WheelEvent('wheel', {
|
|
229
|
-
deltaY,
|
|
230
|
-
clientX: width / 2,
|
|
231
|
-
clientY: 145,
|
|
232
|
-
bubbles: true,
|
|
233
|
-
cancelable: true,
|
|
234
|
-
}),
|
|
235
|
-
)
|
|
236
|
-
flushAnimationFrames()
|
|
237
|
-
await flushPromises()
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
await dispatchWheel(-4000)
|
|
241
|
-
const zoomedDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
242
|
-
expect(zoomedDomain[1] - zoomedDomain[0]).toBeCloseTo(2.5)
|
|
243
|
-
|
|
244
|
-
await wrapper.setProps({
|
|
245
|
-
data: {
|
|
246
|
-
kind: 'points',
|
|
247
|
-
points: [
|
|
248
|
-
{ x: 48, y: 0 },
|
|
249
|
-
{ x: 52, y: 1 },
|
|
250
|
-
],
|
|
251
|
-
},
|
|
252
|
-
})
|
|
253
|
-
await flushPromises()
|
|
254
|
-
const preservedDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
255
|
-
expect(preservedDomain[1] - preservedDomain[0]).toBeCloseTo(2.5)
|
|
256
|
-
|
|
257
|
-
const eventCount = wrapper.emitted('zoom-change')?.length ?? 0
|
|
258
|
-
await dispatchWheel(4000)
|
|
259
|
-
const zoomedOutDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
260
|
-
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(eventCount + 1)
|
|
261
|
-
expect(zoomedOutDomain[1] - zoomedOutDomain[0]).toBeCloseTo(100)
|
|
262
|
-
|
|
263
|
-
const fullDomainEventCount = wrapper.emitted('zoom-change')?.length ?? 0
|
|
264
|
-
await dispatchWheel(4000)
|
|
265
|
-
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(fullDomainEventCount)
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it('allows zooming out when the minimum visible point count blocks zooming in', async () => {
|
|
269
|
-
const wrapper = await mountSizedChart({
|
|
270
|
-
kind: 'points',
|
|
271
|
-
points: [
|
|
272
|
-
{ x: 0, y: 0 },
|
|
273
|
-
{ x: 1, y: 10 },
|
|
274
|
-
{ x: 2, y: 20 },
|
|
275
|
-
],
|
|
276
|
-
})
|
|
277
|
-
const overlay = wrapper.get('.waveform-chart__overlay--independent')
|
|
278
|
-
const width = Number(overlay.attributes('width'))
|
|
279
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
280
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
281
|
-
})
|
|
282
|
-
const dispatchWheel = async (deltaY: number) => {
|
|
283
|
-
overlay.element.dispatchEvent(
|
|
284
|
-
new WheelEvent('wheel', {
|
|
285
|
-
deltaY,
|
|
286
|
-
clientX: width / 2,
|
|
287
|
-
clientY: 145,
|
|
288
|
-
bubbles: true,
|
|
289
|
-
cancelable: true,
|
|
290
|
-
}),
|
|
291
|
-
)
|
|
292
|
-
flushAnimationFrames()
|
|
293
|
-
await flushPromises()
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
await dispatchWheel(-4000)
|
|
297
|
-
const zoomedDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
298
|
-
expect(zoomedDomain[1] - zoomedDomain[0]).toBeCloseTo(0.05)
|
|
299
|
-
|
|
300
|
-
await wrapper.setProps({ minVisiblePoints: 10 })
|
|
301
|
-
await flushPromises()
|
|
302
|
-
const eventCount = wrapper.emitted('zoom-change')?.length ?? 0
|
|
303
|
-
await dispatchWheel(-1000)
|
|
304
|
-
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(eventCount)
|
|
305
|
-
|
|
306
|
-
await dispatchWheel(4000)
|
|
307
|
-
const zoomedOutDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
308
|
-
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(eventCount + 1)
|
|
309
|
-
expect(zoomedOutDomain).toEqual([0, 2])
|
|
310
|
-
})
|
|
311
|
-
})
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { flushPromises } from '@vue/test-utils'
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
|
5
|
-
import WaveformChartView from '../WaveformChartView.vue'
|
|
6
|
-
|
|
7
|
-
describe('WaveformChart viewport lifecycle', () => {
|
|
8
|
-
it('cleans an active shared gesture when its track is removed', async () => {
|
|
9
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
10
|
-
displayMode: 'separated',
|
|
11
|
-
grid: { rowCount: 2, columnCount: 1 },
|
|
12
|
-
})
|
|
13
|
-
const overlay = wrapper.get('.waveform-chart__overlay--shared')
|
|
14
|
-
const width = Number(overlay.attributes('width'))
|
|
15
|
-
const height = Number(overlay.attributes('height'))
|
|
16
|
-
const releasePointerCapture = vi.fn()
|
|
17
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
18
|
-
value: () => ({ left: 0, top: 0, width, height }),
|
|
19
|
-
})
|
|
20
|
-
Object.defineProperty(overlay.element, 'setPointerCapture', { value: vi.fn() })
|
|
21
|
-
Object.defineProperty(overlay.element, 'releasePointerCapture', {
|
|
22
|
-
value: releasePointerCapture,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
const dispatchPointer = (type: string, pointerId: number, clientY: number) => {
|
|
26
|
-
const event = new MouseEvent(type, {
|
|
27
|
-
button: 0,
|
|
28
|
-
clientX: width / 2,
|
|
29
|
-
clientY,
|
|
30
|
-
bubbles: true,
|
|
31
|
-
})
|
|
32
|
-
Object.defineProperty(event, 'pointerId', { value: pointerId })
|
|
33
|
-
overlay.element.dispatchEvent(event)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
dispatchPointer('pointerdown', 41, height * 0.75)
|
|
37
|
-
await flushPromises()
|
|
38
|
-
expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(true)
|
|
39
|
-
|
|
40
|
-
await wrapper.setProps({ data: gridSeries(1) })
|
|
41
|
-
await flushPromises()
|
|
42
|
-
dispatchPointer('pointerup', 41, height * 0.75)
|
|
43
|
-
await flushPromises()
|
|
44
|
-
|
|
45
|
-
expect(releasePointerCapture).toHaveBeenCalledWith(41)
|
|
46
|
-
expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(false)
|
|
47
|
-
|
|
48
|
-
dispatchPointer('pointerdown', 42, height / 2)
|
|
49
|
-
dispatchPointer('pointermove', 42, height / 2 + 20)
|
|
50
|
-
await flushPromises()
|
|
51
|
-
expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(true)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('cleans an active gesture when its overlay leaves the DOM', async () => {
|
|
55
|
-
const wrapper = await mountSizedChart(
|
|
56
|
-
{
|
|
57
|
-
kind: 'points',
|
|
58
|
-
points: [
|
|
59
|
-
{ x: 0, y: 0 },
|
|
60
|
-
{ x: 1, y: 1 },
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
{ displayMode: 'separated' },
|
|
64
|
-
)
|
|
65
|
-
const overlay = wrapper.get('.waveform-chart__overlay--shared')
|
|
66
|
-
const width = Number(overlay.attributes('width'))
|
|
67
|
-
const height = Number(overlay.attributes('height'))
|
|
68
|
-
const releasePointerCapture = vi.fn(() => {
|
|
69
|
-
throw new DOMException('Pointer capture is no longer available', 'NotFoundError')
|
|
70
|
-
})
|
|
71
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
72
|
-
value: () => ({ left: 0, top: 0, width, height }),
|
|
73
|
-
})
|
|
74
|
-
Object.defineProperty(overlay.element, 'setPointerCapture', { value: vi.fn() })
|
|
75
|
-
Object.defineProperty(overlay.element, 'releasePointerCapture', {
|
|
76
|
-
value: releasePointerCapture,
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const down = new MouseEvent('pointerdown', {
|
|
80
|
-
button: 0,
|
|
81
|
-
clientX: width / 2,
|
|
82
|
-
clientY: height / 2,
|
|
83
|
-
bubbles: true,
|
|
84
|
-
})
|
|
85
|
-
Object.defineProperty(down, 'pointerId', { value: 43 })
|
|
86
|
-
overlay.element.dispatchEvent(down)
|
|
87
|
-
await wrapper.setProps({ hiddenSeriesIds: ['series-0'] })
|
|
88
|
-
await flushPromises()
|
|
89
|
-
|
|
90
|
-
expect(wrapper.find('.waveform-chart__overlay--shared').exists()).toBe(false)
|
|
91
|
-
const view = wrapper.findComponent(WaveformChartView)
|
|
92
|
-
const finishViewportDrag = (
|
|
93
|
-
view.vm as unknown as { finishViewportDrag: (event: PointerEvent) => void }
|
|
94
|
-
).finishViewportDrag
|
|
95
|
-
const up = new MouseEvent('pointerup', {
|
|
96
|
-
clientX: width / 2,
|
|
97
|
-
clientY: height / 2,
|
|
98
|
-
bubbles: true,
|
|
99
|
-
})
|
|
100
|
-
Object.defineProperty(up, 'pointerId', { value: 43 })
|
|
101
|
-
finishViewportDrag(up as unknown as PointerEvent)
|
|
102
|
-
await flushPromises()
|
|
103
|
-
|
|
104
|
-
expect(releasePointerCapture).toHaveBeenCalledWith(43)
|
|
105
|
-
expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(false)
|
|
106
|
-
|
|
107
|
-
await wrapper.setProps({ hiddenSeriesIds: [] })
|
|
108
|
-
await flushPromises()
|
|
109
|
-
const nextOverlay = wrapper.get('.waveform-chart__overlay--shared')
|
|
110
|
-
Object.defineProperty(nextOverlay.element, 'getBoundingClientRect', {
|
|
111
|
-
value: () => ({ left: 0, top: 0, width, height }),
|
|
112
|
-
})
|
|
113
|
-
const nextDown = new MouseEvent('pointerdown', {
|
|
114
|
-
button: 0,
|
|
115
|
-
clientX: width / 2,
|
|
116
|
-
clientY: height / 2,
|
|
117
|
-
bubbles: true,
|
|
118
|
-
})
|
|
119
|
-
Object.defineProperty(nextDown, 'pointerId', { value: 44 })
|
|
120
|
-
nextOverlay.element.dispatchEvent(nextDown)
|
|
121
|
-
const nextMove = new MouseEvent('pointermove', {
|
|
122
|
-
clientX: width * 0.75,
|
|
123
|
-
clientY: height / 2,
|
|
124
|
-
bubbles: true,
|
|
125
|
-
})
|
|
126
|
-
Object.defineProperty(nextMove, 'pointerId', { value: 44 })
|
|
127
|
-
nextOverlay.element.dispatchEvent(nextMove)
|
|
128
|
-
await flushPromises()
|
|
129
|
-
|
|
130
|
-
expect(wrapper.find('.waveform-chart__zoom-selection').exists()).toBe(true)
|
|
131
|
-
})
|
|
132
|
-
})
|
|
@@ -1,251 +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 { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
|
6
|
-
|
|
7
|
-
describe('WaveformChart viewport reset', () => {
|
|
8
|
-
const niceExplicitStrategy = {
|
|
9
|
-
type: 'nice' as const,
|
|
10
|
-
bounds: 'end' as const,
|
|
11
|
-
tickCount: 10,
|
|
12
|
-
includeExplicit: true,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
it('resets a shared viewport on double-click and emits a global payload', async () => {
|
|
16
|
-
const wrapper = await mountSizedChart(
|
|
17
|
-
{
|
|
18
|
-
kind: 'points',
|
|
19
|
-
points: [
|
|
20
|
-
{ x: 0, y: 0 },
|
|
21
|
-
{ x: 2, y: 1 },
|
|
22
|
-
],
|
|
23
|
-
},
|
|
24
|
-
{ displayMode: 'separated' },
|
|
25
|
-
)
|
|
26
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
27
|
-
const width = Number(overlay.attributes('width'))
|
|
28
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
29
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
30
|
-
})
|
|
31
|
-
overlay.element.dispatchEvent(
|
|
32
|
-
new WheelEvent('wheel', {
|
|
33
|
-
deltaY: -4000,
|
|
34
|
-
clientX: width / 2,
|
|
35
|
-
clientY: 145,
|
|
36
|
-
bubbles: true,
|
|
37
|
-
cancelable: true,
|
|
38
|
-
}),
|
|
39
|
-
)
|
|
40
|
-
flushAnimationFrames()
|
|
41
|
-
await flushPromises()
|
|
42
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).not.toBe('0')
|
|
43
|
-
|
|
44
|
-
overlay.element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }))
|
|
45
|
-
await flushPromises()
|
|
46
|
-
|
|
47
|
-
expect(wrapper.emitted('zoom-reset')).toEqual([[{}]])
|
|
48
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
49
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('2000')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('resets only the double-clicked independent track and identifies it', async () => {
|
|
53
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
54
|
-
displayMode: 'independent',
|
|
55
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
56
|
-
})
|
|
57
|
-
const overlays = wrapper.findAll('.waveform-chart__overlay--independent')
|
|
58
|
-
for (const overlay of overlays) {
|
|
59
|
-
const width = Number(overlay.attributes('width'))
|
|
60
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
61
|
-
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
|
62
|
-
})
|
|
63
|
-
overlay.element.dispatchEvent(
|
|
64
|
-
new WheelEvent('wheel', {
|
|
65
|
-
deltaY: -4000,
|
|
66
|
-
clientX: width / 2,
|
|
67
|
-
clientY: 130,
|
|
68
|
-
bubbles: true,
|
|
69
|
-
cancelable: true,
|
|
70
|
-
}),
|
|
71
|
-
)
|
|
72
|
-
flushAnimationFrames()
|
|
73
|
-
await flushPromises()
|
|
74
|
-
}
|
|
75
|
-
const startsBeforeReset = wrapper.findAll('.waveform-chart__axis-endpoint--start')
|
|
76
|
-
expect(startsBeforeReset[0].text()).not.toBe('0')
|
|
77
|
-
expect(startsBeforeReset[1].text()).not.toBe('0')
|
|
78
|
-
const secondTrackStart = startsBeforeReset[1].text()
|
|
79
|
-
|
|
80
|
-
overlays[0].element.dispatchEvent(
|
|
81
|
-
new MouseEvent('dblclick', { bubbles: true, cancelable: true }),
|
|
82
|
-
)
|
|
83
|
-
await flushPromises()
|
|
84
|
-
|
|
85
|
-
const startsAfterReset = wrapper.findAll('.waveform-chart__axis-endpoint--start')
|
|
86
|
-
expect(startsAfterReset[0].text()).toBe('0')
|
|
87
|
-
expect(startsAfterReset[1].text()).toBe(secondTrackStart)
|
|
88
|
-
expect(wrapper.emitted('zoom-reset')).toEqual([[{ trackIndex: 0, seriesIds: ['channel-0'] }]])
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('keeps the exposed no-argument resetViewport global', async () => {
|
|
92
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
93
|
-
displayMode: 'independent',
|
|
94
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
95
|
-
})
|
|
96
|
-
const overlay = wrapper.findAll('.waveform-chart__overlay--independent')[0]
|
|
97
|
-
const width = Number(overlay.attributes('width'))
|
|
98
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
99
|
-
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
|
100
|
-
})
|
|
101
|
-
overlay.element.dispatchEvent(
|
|
102
|
-
new WheelEvent('wheel', {
|
|
103
|
-
deltaY: -4000,
|
|
104
|
-
clientX: width / 2,
|
|
105
|
-
clientY: 130,
|
|
106
|
-
bubbles: true,
|
|
107
|
-
cancelable: true,
|
|
108
|
-
}),
|
|
109
|
-
)
|
|
110
|
-
flushAnimationFrames()
|
|
111
|
-
await flushPromises()
|
|
112
|
-
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).not.toBe('0')
|
|
113
|
-
|
|
114
|
-
const chart = wrapper.vm as unknown as { resetViewport: () => void }
|
|
115
|
-
chart.resetViewport()
|
|
116
|
-
await flushPromises()
|
|
117
|
-
|
|
118
|
-
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).toBe('0')
|
|
119
|
-
expect(wrapper.findAll('.waveform-chart__axis-endpoint--end')[0].text()).toBe('1000')
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
it('keeps a controlled shared viewport when the data reference changes', async () => {
|
|
123
|
-
const wrapper = await mountSizedChart(
|
|
124
|
-
{
|
|
125
|
-
kind: 'points',
|
|
126
|
-
points: [
|
|
127
|
-
{ x: 0, y: 0 },
|
|
128
|
-
{ x: 1, y: 1 },
|
|
129
|
-
],
|
|
130
|
-
},
|
|
131
|
-
{ displayMode: 'separated' },
|
|
132
|
-
)
|
|
133
|
-
const chart = wrapper.vm as unknown as {
|
|
134
|
-
setViewportDomain: (domain: [number, number], trackIndex?: number) => void
|
|
135
|
-
}
|
|
136
|
-
chart.setViewportDomain([0.25, 0.75])
|
|
137
|
-
await flushPromises()
|
|
138
|
-
|
|
139
|
-
const startBefore = Number(wrapper.get('.waveform-chart__axis-endpoint--start').text())
|
|
140
|
-
const endBefore = Number(wrapper.get('.waveform-chart__axis-endpoint--end').text())
|
|
141
|
-
expect(startBefore).toBeGreaterThan(0)
|
|
142
|
-
expect(endBefore).toBeLessThan(1000)
|
|
143
|
-
|
|
144
|
-
await wrapper.setProps({
|
|
145
|
-
data: {
|
|
146
|
-
kind: 'points',
|
|
147
|
-
points: [
|
|
148
|
-
{ x: 0, y: 10 },
|
|
149
|
-
{ x: 1, y: 11 },
|
|
150
|
-
],
|
|
151
|
-
},
|
|
152
|
-
})
|
|
153
|
-
await flushPromises()
|
|
154
|
-
|
|
155
|
-
expect(Number(wrapper.get('.waveform-chart__axis-endpoint--start').text())).toBeCloseTo(
|
|
156
|
-
startBefore,
|
|
157
|
-
10,
|
|
158
|
-
)
|
|
159
|
-
expect(Number(wrapper.get('.waveform-chart__axis-endpoint--end').text())).toBeCloseTo(
|
|
160
|
-
endBefore,
|
|
161
|
-
10,
|
|
162
|
-
)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
it('keeps independently controlled track viewports when the data reference changes', async () => {
|
|
166
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
167
|
-
displayMode: 'independent',
|
|
168
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
169
|
-
})
|
|
170
|
-
const chart = wrapper.vm as unknown as {
|
|
171
|
-
setViewportDomain: (domain: [number, number], trackIndex?: number) => void
|
|
172
|
-
}
|
|
173
|
-
chart.setViewportDomain([0.2, 0.8], 0)
|
|
174
|
-
chart.setViewportDomain([0.1, 0.9], 1)
|
|
175
|
-
await flushPromises()
|
|
176
|
-
|
|
177
|
-
const endpoints = () =>
|
|
178
|
-
wrapper.findAll('.waveform-chart__track').map((track) => ({
|
|
179
|
-
start: track.get('.waveform-chart__axis-endpoint--start').text(),
|
|
180
|
-
end: track.get('.waveform-chart__axis-endpoint--end').text(),
|
|
181
|
-
}))
|
|
182
|
-
const endpointsBefore = endpoints()
|
|
183
|
-
expect(Number(endpointsBefore[0].start)).toBeGreaterThan(0)
|
|
184
|
-
expect(Number(endpointsBefore[0].end)).toBeLessThan(1000)
|
|
185
|
-
expect(Number(endpointsBefore[1].start)).toBeGreaterThan(0)
|
|
186
|
-
expect(Number(endpointsBefore[1].end)).toBeLessThan(1000)
|
|
187
|
-
|
|
188
|
-
await wrapper.setProps({ data: gridSeries(2) })
|
|
189
|
-
await flushPromises()
|
|
190
|
-
|
|
191
|
-
const endpointsAfter = endpoints()
|
|
192
|
-
endpointsAfter.forEach((endpoint, index) => {
|
|
193
|
-
expect(Number(endpoint.start)).toBeCloseTo(Number(endpointsBefore[index].start), 10)
|
|
194
|
-
expect(Number(endpoint.end)).toBeCloseTo(Number(endpointsBefore[index].end), 10)
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it('ignores invalid domains and applies viewport constraints', async () => {
|
|
199
|
-
const wrapper = await mountSizedChart(
|
|
200
|
-
{
|
|
201
|
-
kind: 'points',
|
|
202
|
-
points: [
|
|
203
|
-
{ x: 0, y: 0 },
|
|
204
|
-
{ x: 1, y: 1 },
|
|
205
|
-
],
|
|
206
|
-
},
|
|
207
|
-
{ displayMode: 'separated', minZoomSpan: 0.2 },
|
|
208
|
-
)
|
|
209
|
-
const chart = wrapper.vm as unknown as {
|
|
210
|
-
setViewportDomain: (domain: [number, number], trackIndex?: number) => void
|
|
211
|
-
}
|
|
212
|
-
chart.setViewportDomain([Number.NaN, 0.5])
|
|
213
|
-
await flushPromises()
|
|
214
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
215
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('1000')
|
|
216
|
-
|
|
217
|
-
chart.setViewportDomain([0.49, 0.51])
|
|
218
|
-
await flushPromises()
|
|
219
|
-
const start = Number(wrapper.get('.waveform-chart__axis-endpoint--start').text())
|
|
220
|
-
const end = Number(wrapper.get('.waveform-chart__axis-endpoint--end').text())
|
|
221
|
-
expect(end - start).toBeGreaterThanOrEqual(200)
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
it('resets shared and independent explicit domains to their included nice bounds', async () => {
|
|
225
|
-
const shared = await mountSizedChart(
|
|
226
|
-
{
|
|
227
|
-
kind: 'points',
|
|
228
|
-
points: [
|
|
229
|
-
{ x: 0, y: 0 },
|
|
230
|
-
{ x: 4.999999, y: 1 },
|
|
231
|
-
],
|
|
232
|
-
},
|
|
233
|
-
{ initialXDomain: [0, 4.999999], xDomainStrategy: niceExplicitStrategy },
|
|
234
|
-
)
|
|
235
|
-
const independent = await mountSizedChart(gridSeries(2), {
|
|
236
|
-
displayMode: 'independent',
|
|
237
|
-
initialXDomains: { 'channel-0': [0, 4.999999] },
|
|
238
|
-
xDomainStrategy: niceExplicitStrategy,
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
;(shared.vm as unknown as { resetViewport: () => void }).resetViewport()
|
|
242
|
-
;(independent.vm as unknown as { resetViewport: () => void }).resetViewport()
|
|
243
|
-
await flushPromises()
|
|
244
|
-
|
|
245
|
-
expect(shared.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
246
|
-
expect(shared.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
|
247
|
-
const firstTrack = independent.findAll('.waveform-chart__track')[0]
|
|
248
|
-
expect(firstTrack.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
249
|
-
expect(firstTrack.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
|
250
|
-
})
|
|
251
|
-
})
|