fix(chart): scope independent viewport resets
This commit is contained in:
@@ -13,6 +13,7 @@ import type {
|
||||
WaveformTitleOptions,
|
||||
WaveformZeroLineOptions,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
} from '../data/types'
|
||||
import type { WaveformGridOptions } from './grid'
|
||||
|
||||
@@ -82,7 +83,7 @@ export interface WaveformChartEmit {
|
||||
(event: 'point-hover', point: WaveformPoint | null): void
|
||||
(event: 'zoom-change', domain: [number, number]): void
|
||||
(event: 'zoom-end', payload: WaveformZoomEndPayload): void
|
||||
(event: 'zoom-reset'): void
|
||||
(event: 'zoom-reset', payload: WaveformZoomResetPayload): void
|
||||
(event: 'update:annotations', annotations: WaveformAnnotation[]): void
|
||||
(event: 'update:hidden-series-ids', ids: string[]): void
|
||||
(
|
||||
|
||||
@@ -10,6 +10,7 @@ export type {
|
||||
WaveformOverlayMode,
|
||||
WaveformInteractionMode,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
WaveformAnnotationStyle,
|
||||
WaveformAnnotation,
|
||||
WaveformRenderingOptions,
|
||||
|
||||
@@ -346,9 +346,23 @@ export function useWaveformViewport(context: ViewportContext) {
|
||||
}
|
||||
const requestViewportReset = (event: MouseEvent) => {
|
||||
if (isPresentationMode.value || !props.zoomable || !isZoomMode.value) return
|
||||
if (props.displayMode === 'independent') {
|
||||
const target = event.target instanceof Element ? event.target : null
|
||||
const overlay = target?.closest('[data-independent-overlay-index]')
|
||||
const trackIndex = Number(overlay?.getAttribute('data-independent-overlay-index'))
|
||||
const track = trackLayouts.value.find((item) => item.index === trackIndex)
|
||||
if (!track) return
|
||||
event.preventDefault()
|
||||
resetViewport(trackIndex)
|
||||
emit('zoom-reset', {
|
||||
trackIndex,
|
||||
seriesIds: track.legendSeries.map((series) => series.id),
|
||||
})
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
resetViewport()
|
||||
emit('zoom-reset')
|
||||
emit('zoom-reset', {})
|
||||
}
|
||||
return {
|
||||
selectionBox,
|
||||
|
||||
@@ -308,69 +308,4 @@ describe('WaveformChart', () => {
|
||||
expect(wrapper.emitted('zoom-change')?.length ?? 0).toBe(eventCount + 1)
|
||||
expect(zoomedOutDomain).toEqual([0, 2])
|
||||
})
|
||||
|
||||
it('resets a shared viewport on double-click and emits zoom-reset', async () => {
|
||||
const wrapper = await mountSizedChart({
|
||||
kind: 'points',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 2, y: 1 },
|
||||
],
|
||||
})
|
||||
const overlay = wrapper.get('.waveform-chart__overlay')
|
||||
const width = Number(overlay.attributes('width'))
|
||||
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
||||
})
|
||||
overlay.element.dispatchEvent(
|
||||
new WheelEvent('wheel', {
|
||||
deltaY: -4000,
|
||||
clientX: width / 2,
|
||||
clientY: 145,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}),
|
||||
)
|
||||
flushAnimationFrames()
|
||||
await flushPromises()
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).not.toBe('0')
|
||||
|
||||
overlay.element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }))
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.emitted('zoom-reset')).toHaveLength(1)
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('2000')
|
||||
})
|
||||
|
||||
it('exposes resetViewport for independent tracks', async () => {
|
||||
const wrapper = await mountSizedChart(gridSeries(2), {
|
||||
displayMode: 'independent',
|
||||
grid: { rowCount: 1, columnCount: 2 },
|
||||
})
|
||||
const overlay = wrapper.findAll('.waveform-chart__overlay--independent')[0]
|
||||
const width = Number(overlay.attributes('width'))
|
||||
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
||||
})
|
||||
overlay.element.dispatchEvent(
|
||||
new WheelEvent('wheel', {
|
||||
deltaY: -4000,
|
||||
clientX: width / 2,
|
||||
clientY: 130,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}),
|
||||
)
|
||||
flushAnimationFrames()
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).not.toBe('0')
|
||||
|
||||
const chart = wrapper.vm as unknown as { resetViewport: () => void }
|
||||
chart.resetViewport()
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).toBe('0')
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--end')[0].text()).toBe('1000')
|
||||
})
|
||||
})
|
||||
|
||||
114
src/components/waveformChartCases/viewportReset.test.ts
Normal file
114
src/components/waveformChartCases/viewportReset.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { flushAnimationFrames } from '../../test/setup'
|
||||
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
||||
|
||||
describe('WaveformChart viewport reset', () => {
|
||||
it('resets a shared viewport on double-click and emits a global payload', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
kind: 'points',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 2, y: 1 },
|
||||
],
|
||||
},
|
||||
{ displayMode: 'separated' },
|
||||
)
|
||||
const overlay = wrapper.get('.waveform-chart__overlay')
|
||||
const width = Number(overlay.attributes('width'))
|
||||
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
||||
})
|
||||
overlay.element.dispatchEvent(
|
||||
new WheelEvent('wheel', {
|
||||
deltaY: -4000,
|
||||
clientX: width / 2,
|
||||
clientY: 145,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}),
|
||||
)
|
||||
flushAnimationFrames()
|
||||
await flushPromises()
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).not.toBe('0')
|
||||
|
||||
overlay.element.dispatchEvent(new MouseEvent('dblclick', { bubbles: true, cancelable: true }))
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.emitted('zoom-reset')).toEqual([[{}]])
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('2000')
|
||||
})
|
||||
|
||||
it('resets only the double-clicked independent track and identifies it', async () => {
|
||||
const wrapper = await mountSizedChart(gridSeries(2), {
|
||||
displayMode: 'independent',
|
||||
grid: { rowCount: 1, columnCount: 2 },
|
||||
})
|
||||
const overlays = wrapper.findAll('.waveform-chart__overlay--independent')
|
||||
for (const overlay of overlays) {
|
||||
const width = Number(overlay.attributes('width'))
|
||||
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
||||
})
|
||||
overlay.element.dispatchEvent(
|
||||
new WheelEvent('wheel', {
|
||||
deltaY: -4000,
|
||||
clientX: width / 2,
|
||||
clientY: 130,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}),
|
||||
)
|
||||
flushAnimationFrames()
|
||||
await flushPromises()
|
||||
}
|
||||
const startsBeforeReset = wrapper.findAll('.waveform-chart__axis-endpoint--start')
|
||||
expect(startsBeforeReset[0].text()).not.toBe('0')
|
||||
expect(startsBeforeReset[1].text()).not.toBe('0')
|
||||
const secondTrackStart = startsBeforeReset[1].text()
|
||||
|
||||
overlays[0].element.dispatchEvent(
|
||||
new MouseEvent('dblclick', { bubbles: true, cancelable: true }),
|
||||
)
|
||||
await flushPromises()
|
||||
|
||||
const startsAfterReset = wrapper.findAll('.waveform-chart__axis-endpoint--start')
|
||||
expect(startsAfterReset[0].text()).toBe('0')
|
||||
expect(startsAfterReset[1].text()).toBe(secondTrackStart)
|
||||
expect(wrapper.emitted('zoom-reset')).toEqual([[{ trackIndex: 0, seriesIds: ['channel-0'] }]])
|
||||
})
|
||||
|
||||
it('keeps the exposed no-argument resetViewport global', async () => {
|
||||
const wrapper = await mountSizedChart(gridSeries(2), {
|
||||
displayMode: 'independent',
|
||||
grid: { rowCount: 1, columnCount: 2 },
|
||||
})
|
||||
const overlay = wrapper.findAll('.waveform-chart__overlay--independent')[0]
|
||||
const width = Number(overlay.attributes('width'))
|
||||
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
||||
value: () => ({ left: 0, top: 0, width, height: 260 }),
|
||||
})
|
||||
overlay.element.dispatchEvent(
|
||||
new WheelEvent('wheel', {
|
||||
deltaY: -4000,
|
||||
clientX: width / 2,
|
||||
clientY: 130,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
}),
|
||||
)
|
||||
flushAnimationFrames()
|
||||
await flushPromises()
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).not.toBe('0')
|
||||
|
||||
const chart = wrapper.vm as unknown as { resetViewport: () => void }
|
||||
chart.resetViewport()
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).toBe('0')
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--end')[0].text()).toBe('1000')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user