waveform-analysis 0.1.25 → 0.1.27
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 +6 -5
- package/dist/index.cjs +1 -1
- package/dist/index.js +497 -493
- package/package.json +1 -1
- package/src/components/core/trackLayoutBuilder.ts +1 -0
- package/src/components/interaction/useWaveformZoom.ts +12 -8
- package/src/components/rendering/WaveformTrack.vue +1 -1
- package/src/components/rendering/WaveformTrackAxes.vue +5 -7
- package/src/components/waveformChartCases/layoutAndDomains.test.ts +4 -2
- package/src/components/waveformChartCases/presentationAndAxes.test.ts +26 -6
- 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 +51 -3
- package/src/components/waveformChartCases/wheelZoomOut.test.ts +114 -0
package/package.json
CHANGED
|
@@ -86,6 +86,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
86
86
|
? scaleLinear(
|
|
87
87
|
options.initialXDomains?.[displayTrack.id] ??
|
|
88
88
|
options.initialXDomains?.[series.id] ??
|
|
89
|
+
options.initialXDomain ??
|
|
89
90
|
displayTrack.xDomain,
|
|
90
91
|
[0, cell.width],
|
|
91
92
|
)
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
select,
|
|
4
4
|
zoom,
|
|
5
5
|
zoomIdentity,
|
|
6
|
+
zoomTransform,
|
|
6
7
|
type D3ZoomEvent,
|
|
7
8
|
type ZoomBehavior,
|
|
8
9
|
type ZoomTransform,
|
|
@@ -237,6 +238,15 @@ export function useWaveformZoom(context: ZoomContext) {
|
|
|
237
238
|
const tracks = trackLayouts.value.filter((track) => track.hasVisibleSeries)
|
|
238
239
|
return tracks.length > 0 && tracks.every(canZoomTrack)
|
|
239
240
|
}
|
|
241
|
+
const canHandleWheelZoom = (event: Event, canZoomIn: boolean): boolean => {
|
|
242
|
+
if (event.type !== 'wheel') return false
|
|
243
|
+
const deltaY = (event as WheelEvent).deltaY
|
|
244
|
+
if (deltaY < 0) return canZoomIn
|
|
245
|
+
if (deltaY > 0) {
|
|
246
|
+
return zoomTransform(event.currentTarget as Element).k > ZOOM_CONSTRAINTS.MIN_SCALE
|
|
247
|
+
}
|
|
248
|
+
return false
|
|
249
|
+
}
|
|
240
250
|
const configureZoom = () => {
|
|
241
251
|
clearZoomBindings()
|
|
242
252
|
if (
|
|
@@ -256,10 +266,7 @@ export function useWaveformZoom(context: ZoomContext) {
|
|
|
256
266
|
if (!overlay) return
|
|
257
267
|
const dataDomain = resolveInitialTrackDomain(track)
|
|
258
268
|
const behavior = zoom<SVGRectElement, unknown>()
|
|
259
|
-
.filter(
|
|
260
|
-
(event) =>
|
|
261
|
-
event.type === 'wheel' && (event as WheelEvent).deltaY < 0 && canZoomTrack(track),
|
|
262
|
-
)
|
|
269
|
+
.filter((event) => canHandleWheelZoom(event, canZoomTrack(track)))
|
|
263
270
|
.scaleExtent([1, resolveMaximumZoomScale(dataDomain)])
|
|
264
271
|
.extent([
|
|
265
272
|
[0, 0],
|
|
@@ -287,10 +294,7 @@ export function useWaveformZoom(context: ZoomContext) {
|
|
|
287
294
|
const overlay = sharedOverlayElement.value
|
|
288
295
|
if (!overlay) return
|
|
289
296
|
const behavior = zoom<SVGRectElement, unknown>()
|
|
290
|
-
.filter(
|
|
291
|
-
(event) =>
|
|
292
|
-
event.type === 'wheel' && (event as WheelEvent).deltaY < 0 && canZoomSharedTracks(),
|
|
293
|
-
)
|
|
297
|
+
.filter((event) => canHandleWheelZoom(event, canZoomSharedTracks()))
|
|
294
298
|
.scaleExtent([1, resolveMaximumZoomScale(initialXDomain.value)])
|
|
295
299
|
.extent([
|
|
296
300
|
[0, 0],
|
|
@@ -103,14 +103,14 @@ watch(
|
|
|
103
103
|
|
|
104
104
|
<template>
|
|
105
105
|
<g
|
|
106
|
-
v-if="track.showXAxis
|
|
106
|
+
v-if="track.showXAxis"
|
|
107
107
|
ref="xAxisElement"
|
|
108
108
|
class="waveform-track__axis waveform-track__axis--x waveform-chart__axis waveform-chart__axis--x"
|
|
109
109
|
:class="{ 'waveform-track__axis--line-hidden': axes?.x?.lineVisible === false }"
|
|
110
110
|
:transform="`translate(0, ${track.height})`"
|
|
111
111
|
/>
|
|
112
112
|
<g
|
|
113
|
-
v-if="track.showXAxis
|
|
113
|
+
v-if="track.showXAxis"
|
|
114
114
|
class="waveform-track__axis-endpoints waveform-chart__axis-endpoints"
|
|
115
115
|
:transform="`translate(0, ${track.height})`"
|
|
116
116
|
font-family="sans-serif"
|
|
@@ -137,7 +137,7 @@ watch(
|
|
|
137
137
|
</text>
|
|
138
138
|
</g>
|
|
139
139
|
<text
|
|
140
|
-
v-if="track.showXAxis && track.xAxisExponent
|
|
140
|
+
v-if="track.showXAxis && track.xAxisExponent"
|
|
141
141
|
class="waveform-track__axis-exponent waveform-track__axis-exponent--x waveform-chart__axis-exponent waveform-chart__axis-exponent--x"
|
|
142
142
|
:x="track.width ?? innerWidth"
|
|
143
143
|
:y="track.height + 27"
|
|
@@ -148,7 +148,7 @@ watch(
|
|
|
148
148
|
</text>
|
|
149
149
|
|
|
150
150
|
<g
|
|
151
|
-
v-for="axis in track.isEmpty
|
|
151
|
+
v-for="axis in track.isEmpty ? [] : track.yAxes"
|
|
152
152
|
:key="`y-axis-${track.index}-${axis.index}`"
|
|
153
153
|
:ref="(element) => setYAxisElement(element, axis.index)"
|
|
154
154
|
class="waveform-track__axis waveform-track__axis--y waveform-chart__axis waveform-chart__axis--y"
|
|
@@ -161,9 +161,7 @@ watch(
|
|
|
161
161
|
:transform="`translate(${axis.x}, 0)`"
|
|
162
162
|
/>
|
|
163
163
|
<text
|
|
164
|
-
v-for="axis in track.isEmpty
|
|
165
|
-
? []
|
|
166
|
-
: track.yAxes.filter((item) => item.exponentLabel)"
|
|
164
|
+
v-for="axis in track.isEmpty ? [] : track.yAxes.filter((item) => item.exponentLabel)"
|
|
167
165
|
:key="`y-axis-exponent-${track.index}-${axis.index}`"
|
|
168
166
|
class="waveform-track__axis-exponent waveform-track__axis-exponent--y waveform-chart__axis-exponent waveform-chart__axis-exponent--y"
|
|
169
167
|
:data-y-axis-index="axis.index"
|
|
@@ -225,7 +225,7 @@ describe('WaveformChart', () => {
|
|
|
225
225
|
}
|
|
226
226
|
})
|
|
227
227
|
|
|
228
|
-
it('uses
|
|
228
|
+
it('uses the shared initial x domain for every independent track by default', async () => {
|
|
229
229
|
const wrapper = await mountSizedChart(
|
|
230
230
|
{
|
|
231
231
|
kind: 'series',
|
|
@@ -262,7 +262,9 @@ describe('WaveformChart', () => {
|
|
|
262
262
|
)
|
|
263
263
|
|
|
264
264
|
const tracks = wrapper.findAll('.waveform-chart__track')
|
|
265
|
-
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--
|
|
265
|
+
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('-8.00')
|
|
266
|
+
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('5.00')
|
|
267
|
+
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('-8.00')
|
|
266
268
|
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('5.00')
|
|
267
269
|
})
|
|
268
270
|
|
|
@@ -146,7 +146,7 @@ describe('WaveformChart', () => {
|
|
|
146
146
|
kind: 'points',
|
|
147
147
|
points: [
|
|
148
148
|
{ x: 0, y: -1 },
|
|
149
|
-
{ x:
|
|
149
|
+
{ x: 10_000, y: 1 },
|
|
150
150
|
],
|
|
151
151
|
},
|
|
152
152
|
},
|
|
@@ -227,8 +227,8 @@ describe('WaveformChart', () => {
|
|
|
227
227
|
data: {
|
|
228
228
|
kind: 'points',
|
|
229
229
|
points: [
|
|
230
|
-
{ x: 0, y:
|
|
231
|
-
{ x:
|
|
230
|
+
{ x: 0, y: 10_000 },
|
|
231
|
+
{ x: 10_000, y: 20_000 },
|
|
232
232
|
],
|
|
233
233
|
},
|
|
234
234
|
},
|
|
@@ -239,7 +239,7 @@ describe('WaveformChart', () => {
|
|
|
239
239
|
kind: 'points',
|
|
240
240
|
points: [
|
|
241
241
|
{ x: 0, y: 2 },
|
|
242
|
-
{ x:
|
|
242
|
+
{ x: 10_000, y: 3 },
|
|
243
243
|
],
|
|
244
244
|
},
|
|
245
245
|
},
|
|
@@ -252,6 +252,8 @@ describe('WaveformChart', () => {
|
|
|
252
252
|
annotations: [{ id: 'note', seriesId: 'first', x: 0.5, y: 0, text: 'hidden note' }],
|
|
253
253
|
zeroLine: { visible: true },
|
|
254
254
|
title: { text: 'hidden title' },
|
|
255
|
+
axes: { x: { lineVisible: false }, y: { lineVisible: false } },
|
|
256
|
+
frameStyle: { borderColor: '#dc2626', borderWidth: 2, borderStyle: 'dashed' as const },
|
|
255
257
|
}
|
|
256
258
|
const regularWrapper = await mountSizedChart(data, sharedProps)
|
|
257
259
|
const wrapper = await mountSizedChart(data, {
|
|
@@ -285,13 +287,31 @@ describe('WaveformChart', () => {
|
|
|
285
287
|
expect(wrapper.find('.waveform-chart__overlay--independent').exists()).toBe(true)
|
|
286
288
|
expect(wrapper.get('.waveform-chart__title-area').attributes('aria-hidden')).toBe('true')
|
|
287
289
|
expect(wrapper.find('.waveform-chart__title-visual').exists()).toBe(false)
|
|
288
|
-
|
|
290
|
+
const xAxis = wrapper.get('.waveform-chart__axis--x')
|
|
291
|
+
const yAxes = wrapper.findAll('.waveform-chart__axis--y')
|
|
292
|
+
expect(yAxes).toHaveLength(2)
|
|
293
|
+
expect(xAxis.findAll('.tick line').length).toBeGreaterThan(0)
|
|
294
|
+
expect(xAxis.findAll('.tick text').length).toBeGreaterThan(0)
|
|
295
|
+
yAxes.forEach((axis) => {
|
|
296
|
+
expect(axis.findAll('.tick line').length).toBeGreaterThan(0)
|
|
297
|
+
expect(axis.findAll('.tick text').length).toBeGreaterThan(0)
|
|
298
|
+
expect(axis.get('path.domain').attributes('display')).toBe('none')
|
|
299
|
+
})
|
|
300
|
+
expect(xAxis.get('path.domain').attributes('display')).toBe('none')
|
|
301
|
+
expect(wrapper.findAll('.waveform-chart__axis-endpoint')).toHaveLength(2)
|
|
302
|
+
expect(wrapper.get('.waveform-chart__axis-exponent--x').text()).not.toBe('')
|
|
303
|
+
expect(wrapper.get('.waveform-chart__axis-exponent--y').text()).not.toBe('')
|
|
289
304
|
expect(wrapper.find('.waveform-chart__grid').exists()).toBe(false)
|
|
290
|
-
expect(wrapper.
|
|
305
|
+
expect(wrapper.get('.waveform-chart__plot-frame').attributes()).toMatchObject({
|
|
306
|
+
stroke: '#dc2626',
|
|
307
|
+
'stroke-width': '2',
|
|
308
|
+
'stroke-dasharray': '6 4',
|
|
309
|
+
})
|
|
291
310
|
expect(wrapper.find('.waveform-chart__plot-background').exists()).toBe(false)
|
|
292
311
|
expect(wrapper.find('.waveform-chart__watermark').exists()).toBe(false)
|
|
293
312
|
expect(wrapper.find('.waveform-chart__legend-layer').exists()).toBe(false)
|
|
294
313
|
expect(wrapper.find('.waveform-chart__label').exists()).toBe(false)
|
|
314
|
+
expect(wrapper.find('.waveform-chart__y-axis-label').exists()).toBe(false)
|
|
295
315
|
expect(wrapper.find('.waveform-chart__zero-line').exists()).toBe(false)
|
|
296
316
|
expect(wrapper.find('.waveform-annotation-layer').exists()).toBe(false)
|
|
297
317
|
expect(wrapper.find('.ant-pagination').exists()).toBe(false)
|
|
@@ -38,6 +38,21 @@ describe('WaveformChart', () => {
|
|
|
38
38
|
expect(domain[1]).toBeLessThanOrEqual(1)
|
|
39
39
|
expect(endpoints()[0]).not.toBe(initialEndpoints[0])
|
|
40
40
|
expect(endpoints()[1]).toBe(initialEndpoints[1])
|
|
41
|
+
|
|
42
|
+
overlays[0].element.dispatchEvent(
|
|
43
|
+
new WheelEvent('wheel', {
|
|
44
|
+
deltaY: 4_000,
|
|
45
|
+
clientX: firstWidth - 1,
|
|
46
|
+
clientY: 130,
|
|
47
|
+
bubbles: true,
|
|
48
|
+
cancelable: true,
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
flushAnimationFrames()
|
|
52
|
+
await flushPromises()
|
|
53
|
+
|
|
54
|
+
expect(endpoints()[0]).toBe(initialEndpoints[0])
|
|
55
|
+
expect(endpoints()[1]).toBe(initialEndpoints[1])
|
|
41
56
|
})
|
|
42
57
|
|
|
43
58
|
it('emits one zoom-end payload after a shared zoom gesture completes', async () => {
|
|
@@ -207,7 +207,7 @@ describe('WaveformChart', () => {
|
|
|
207
207
|
expect(secondDomain[1] - secondDomain[0]).toBeCloseTo(10)
|
|
208
208
|
})
|
|
209
209
|
|
|
210
|
-
it('
|
|
210
|
+
it('zooms a shared viewport back out after loading a narrower data window', async () => {
|
|
211
211
|
const wrapper = await mountSizedChart(
|
|
212
212
|
{
|
|
213
213
|
kind: 'points',
|
|
@@ -256,9 +256,57 @@ describe('WaveformChart', () => {
|
|
|
256
256
|
|
|
257
257
|
const eventCount = wrapper.emitted('zoom-change')?.length ?? 0
|
|
258
258
|
await dispatchWheel(4000)
|
|
259
|
-
const
|
|
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)
|
|
260
304
|
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(eventCount)
|
|
261
|
-
|
|
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])
|
|
262
310
|
})
|
|
263
311
|
|
|
264
312
|
it('resets a shared viewport on double-click and emits zoom-reset', async () => {
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { flushPromises } from '@vue/test-utils'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { flushAnimationFrames } from '../../test/setup'
|
|
5
|
+
import { mountSizedChart } from '../../test/waveformChart'
|
|
6
|
+
|
|
7
|
+
describe('WaveformChart wheel zoom out', () => {
|
|
8
|
+
it('restores an independent initial domain after replacing data with a narrow window', async () => {
|
|
9
|
+
const createData = (start: number, end: number) => ({
|
|
10
|
+
kind: 'series' as const,
|
|
11
|
+
series: [
|
|
12
|
+
{
|
|
13
|
+
id: 'channel-a',
|
|
14
|
+
name: '通道 A',
|
|
15
|
+
data: {
|
|
16
|
+
kind: 'points' as const,
|
|
17
|
+
points: [
|
|
18
|
+
{ x: start, y: 0 },
|
|
19
|
+
{ x: end, y: 1 },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
})
|
|
25
|
+
const wrapper = await mountSizedChart(createData(-5, 5), {
|
|
26
|
+
displayMode: 'independent',
|
|
27
|
+
initialXDomain: [-5, 5],
|
|
28
|
+
})
|
|
29
|
+
const overlay = wrapper.get('.waveform-chart__overlay--independent')
|
|
30
|
+
const overlayWidth = Number(overlay.attributes('width'))
|
|
31
|
+
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
32
|
+
value: () => ({ left: 0, top: 0, width: overlayWidth, height: 290 }),
|
|
33
|
+
})
|
|
34
|
+
const dispatchWheel = async (deltaY: number) => {
|
|
35
|
+
overlay.element.dispatchEvent(
|
|
36
|
+
new WheelEvent('wheel', {
|
|
37
|
+
deltaY,
|
|
38
|
+
clientX: overlayWidth / 2,
|
|
39
|
+
clientY: 145,
|
|
40
|
+
bubbles: true,
|
|
41
|
+
cancelable: true,
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
flushAnimationFrames()
|
|
45
|
+
await flushPromises()
|
|
46
|
+
}
|
|
47
|
+
const endpoints = () => ({
|
|
48
|
+
start: wrapper.get('.waveform-chart__axis-endpoint--start').text(),
|
|
49
|
+
end: wrapper.get('.waveform-chart__axis-endpoint--end').text(),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
expect(endpoints()).toEqual({ start: '-5.00', end: '5.00' })
|
|
53
|
+
await dispatchWheel(-4000)
|
|
54
|
+
expect(endpoints()).not.toEqual({ start: '-5.00', end: '5.00' })
|
|
55
|
+
|
|
56
|
+
await wrapper.setProps({ data: createData(-0.125, 0.125) })
|
|
57
|
+
await flushPromises()
|
|
58
|
+
await dispatchWheel(4000)
|
|
59
|
+
|
|
60
|
+
expect(endpoints()).toEqual({ start: '-5.00', end: '5.00' })
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('emits one zoom-end payload after zooming a shared viewport out', async () => {
|
|
64
|
+
vi.useFakeTimers()
|
|
65
|
+
try {
|
|
66
|
+
const wrapper = await mountSizedChart({
|
|
67
|
+
kind: 'points',
|
|
68
|
+
points: [
|
|
69
|
+
{ x: 0, y: 0 },
|
|
70
|
+
{ x: 2, y: 1 },
|
|
71
|
+
],
|
|
72
|
+
})
|
|
73
|
+
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
74
|
+
const overlayWidth = Number(overlay.attributes('width'))
|
|
75
|
+
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
76
|
+
value: () => ({ left: 0, top: 0, width: overlayWidth, height: 290 }),
|
|
77
|
+
})
|
|
78
|
+
const dispatchWheel = (deltaY: number) =>
|
|
79
|
+
overlay.element.dispatchEvent(
|
|
80
|
+
new WheelEvent('wheel', {
|
|
81
|
+
deltaY,
|
|
82
|
+
clientX: overlayWidth / 2,
|
|
83
|
+
clientY: 145,
|
|
84
|
+
bubbles: true,
|
|
85
|
+
cancelable: true,
|
|
86
|
+
}),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
dispatchWheel(-4000)
|
|
90
|
+
flushAnimationFrames()
|
|
91
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
92
|
+
await flushPromises()
|
|
93
|
+
const zoomedDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
94
|
+
const zoomedSpan = zoomedDomain[1] - zoomedDomain[0]
|
|
95
|
+
|
|
96
|
+
dispatchWheel(1000)
|
|
97
|
+
flushAnimationFrames()
|
|
98
|
+
expect(wrapper.emitted('zoom-end')).toHaveLength(1)
|
|
99
|
+
await vi.advanceTimersByTimeAsync(200)
|
|
100
|
+
await flushPromises()
|
|
101
|
+
|
|
102
|
+
const zoomedOutPayload = wrapper.emitted('zoom-end')?.at(-1)?.[0] as {
|
|
103
|
+
start: number
|
|
104
|
+
end: number
|
|
105
|
+
gesture: string
|
|
106
|
+
}
|
|
107
|
+
expect(wrapper.emitted('zoom-end')).toHaveLength(2)
|
|
108
|
+
expect(zoomedOutPayload.end - zoomedOutPayload.start).toBeGreaterThan(zoomedSpan)
|
|
109
|
+
expect(zoomedOutPayload.gesture).toBe('wheel')
|
|
110
|
+
} finally {
|
|
111
|
+
vi.useRealTimers()
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
})
|