waveform-analysis 0.1.46 → 0.1.48
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 +44 -30
- package/dist/index.cjs +1 -1
- package/dist/index.js +460 -461
- package/dist/types/components/core/grid.d.ts +3 -0
- package/dist/types/components/core/layout.d.ts +2 -2
- package/dist/types/components/core/trackLayoutBuilder.d.ts +1 -0
- package/dist/types/components/core/types.d.ts +2 -1
- package/dist/types/components/interaction/useWaveformViewport.d.ts +2 -1
- package/dist/types/types/chart.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/WaveformChartView.vue +2 -2
- package/src/components/core/grid.test.ts +13 -1
- package/src/components/core/grid.ts +14 -4
- package/src/components/core/layout.ts +15 -6
- package/src/components/core/trackLayoutBuilder.ts +17 -23
- package/src/components/core/types.ts +2 -1
- package/src/components/core/useWaveformLayout.ts +24 -12
- package/src/components/core/yAxisNice.test.ts +174 -0
- package/src/components/interaction/useWaveformHover.ts +2 -1
- package/src/components/interaction/useWaveformViewport.ts +20 -15
- package/src/components/interaction/useWaveformZoom.ts +1 -1
- package/src/components/rendering/WaveformTrack.vue +1 -0
- package/src/components/rendering/WaveformTrackAxes.vue +3 -2
- package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +49 -0
- package/src/components/waveformChartCases/trackOrder.test.ts +261 -0
- package/src/demo/xAxisLabelControls.test.ts +1 -1
- package/src/types/chart.ts +2 -0
|
@@ -3,11 +3,8 @@ import { computed, nextTick, shallowRef, type ComputedRef, type Ref, type Shallo
|
|
|
3
3
|
import { MINIMUM_SELECTION_SIZE } from '../core/constants'
|
|
4
4
|
import type { DisplayTrack, TrackLayout } from '../core/types'
|
|
5
5
|
import { hasFixedYDomainForTrack } from '../core/yDomain'
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
ViewportSelectionState,
|
|
9
|
-
WaveformChartEmit,
|
|
10
|
-
} from '../core/waveformChartTypes'
|
|
6
|
+
import type { ResolvedWaveformChartProps, ViewportSelectionState } from '../core/waveformChartTypes'
|
|
7
|
+
import type { WaveformChartEmit } from '../core/waveformChartTypes'
|
|
11
8
|
import type { AnnotationSeriesCandidate } from '../annotation'
|
|
12
9
|
import { tryReleasePointerCapture } from './pointerCapture'
|
|
13
10
|
import { transitionViewportInteraction } from './viewportInteractionState'
|
|
@@ -104,10 +101,12 @@ export function useWaveformViewport(context: ViewportContext) {
|
|
|
104
101
|
}
|
|
105
102
|
const currentYDomains = (): Record<string, [number, number]> =>
|
|
106
103
|
Object.fromEntries(
|
|
107
|
-
trackLayouts.value
|
|
108
|
-
track
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
trackLayouts.value
|
|
105
|
+
.filter((track) => track.hasVisibleSeries)
|
|
106
|
+
.map((track) => [
|
|
107
|
+
track.series?.trackId ?? track.series?.id ?? track.id,
|
|
108
|
+
track.yScale.domain() as [number, number],
|
|
109
|
+
]),
|
|
111
110
|
)
|
|
112
111
|
const beginViewportDrag = (event: PointerEvent, trackIndex: number, independent: boolean) => {
|
|
113
112
|
if (isPresentationMode.value) return
|
|
@@ -142,8 +141,10 @@ export function useWaveformViewport(context: ViewportContext) {
|
|
|
142
141
|
const beginSharedViewportDrag = (event: PointerEvent) => {
|
|
143
142
|
if (!sharedOverlayElement.value) return
|
|
144
143
|
const [x, y] = pointer(event, sharedOverlayElement.value)
|
|
144
|
+
const pointedTrack = resolveTrackAtPointer(x, y)
|
|
145
145
|
const track =
|
|
146
|
-
|
|
146
|
+
(pointedTrack?.hasVisibleSeries ? pointedTrack : undefined) ??
|
|
147
|
+
trackLayouts.value.find((item) => item.hasVisibleSeries)
|
|
147
148
|
if (track) beginViewportDrag(event, track.index, false)
|
|
148
149
|
}
|
|
149
150
|
const applyPan = (active: ViewportSelectionState, track: TrackLayout) => {
|
|
@@ -166,7 +167,9 @@ export function useWaveformViewport(context: ViewportContext) {
|
|
|
166
167
|
} else {
|
|
167
168
|
sharedTransform.value = transformForDomain(nextX, sourceXDomain, innerWidth.value)
|
|
168
169
|
}
|
|
169
|
-
const targets = active.independent
|
|
170
|
+
const targets = active.independent
|
|
171
|
+
? [track]
|
|
172
|
+
: trackLayouts.value.filter((target) => target.hasVisibleSeries)
|
|
170
173
|
const nextIndependentDomains = { ...independentYDomains.value }
|
|
171
174
|
const nextSharedDomains = { ...sharedYDomains.value }
|
|
172
175
|
targets.forEach((target) => {
|
|
@@ -174,7 +177,7 @@ export function useWaveformViewport(context: ViewportContext) {
|
|
|
174
177
|
if (chartTrack && hasFixedYDomainForTrack(chartTrack, props.yDomain, props.yDomains)) {
|
|
175
178
|
return
|
|
176
179
|
}
|
|
177
|
-
const key = target.series
|
|
180
|
+
const key = target.series?.trackId ?? target.series?.id ?? target.id
|
|
178
181
|
const source = active.yDomains[key] ?? (target.yScale.domain() as [number, number])
|
|
179
182
|
const boundary = chartTrack?.yDomain ?? source
|
|
180
183
|
const ySpan = source[1] - source[0]
|
|
@@ -251,16 +254,18 @@ export function useWaveformViewport(context: ViewportContext) {
|
|
|
251
254
|
} else {
|
|
252
255
|
sharedTransform.value = transformForDomain(xDomain, baseXDomain, innerWidth.value)
|
|
253
256
|
}
|
|
254
|
-
const targets = active.independent
|
|
257
|
+
const targets = active.independent
|
|
258
|
+
? [track]
|
|
259
|
+
: trackLayouts.value.filter((target) => target.hasVisibleSeries)
|
|
255
260
|
const yRanges = Object.fromEntries(
|
|
256
261
|
targets.map((target) => [
|
|
257
|
-
target.series
|
|
262
|
+
target.series?.trackId ?? target.series?.id ?? target.id,
|
|
258
263
|
target.yScale.domain() as [number, number],
|
|
259
264
|
]),
|
|
260
265
|
)
|
|
261
266
|
emit('zoom-change', xDomain)
|
|
262
267
|
if (active.independent) {
|
|
263
|
-
const yDomain = yRanges[track.series
|
|
268
|
+
const yDomain = yRanges[track.series?.trackId ?? track.series?.id ?? track.id]
|
|
264
269
|
emit('zoom-end', {
|
|
265
270
|
start: xDomain[0],
|
|
266
271
|
end: xDomain[1],
|
|
@@ -177,7 +177,7 @@ export function useWaveformZoom(context: ZoomContext) {
|
|
|
177
177
|
end: domain[1],
|
|
178
178
|
yRanges: Object.fromEntries(
|
|
179
179
|
visibleTracks.map((track) => [
|
|
180
|
-
track.series
|
|
180
|
+
track.series?.trackId ?? track.series?.id ?? track.id,
|
|
181
181
|
track.yScale.domain() as [number, number],
|
|
182
182
|
]),
|
|
183
183
|
),
|
|
@@ -67,6 +67,7 @@ const resolvedFrameStyle = computed(() => {
|
|
|
67
67
|
class="waveform-track waveform-chart__track"
|
|
68
68
|
:class="{ 'waveform-track--empty waveform-chart__track--empty': track.isEmpty }"
|
|
69
69
|
:data-track-index="track.index"
|
|
70
|
+
:data-track-id="track.id"
|
|
70
71
|
:data-track-empty="track.isEmpty || undefined"
|
|
71
72
|
:data-track-left="track.left"
|
|
72
73
|
:data-track-width="track.width"
|
|
@@ -164,6 +164,7 @@ watch(
|
|
|
164
164
|
track.hasVisibleSeries &&
|
|
165
165
|
track.seriesList.length === 1 &&
|
|
166
166
|
track.showYAxisLabel &&
|
|
167
|
+
track.series &&
|
|
167
168
|
resolveYAxisLabel(track.series) &&
|
|
168
169
|
shouldShowYAxisLabel(track.height, track.index)
|
|
169
170
|
"
|
|
@@ -178,12 +179,12 @@ watch(
|
|
|
178
179
|
/>
|
|
179
180
|
<text
|
|
180
181
|
class="waveform-track__y-axis-label waveform-chart__y-axis-label"
|
|
181
|
-
:fill="track.series
|
|
182
|
+
:fill="track.series?.color"
|
|
182
183
|
:transform="`translate(${track.yAxisLabelX}, ${track.height / 2}) rotate(-90)`"
|
|
183
184
|
text-anchor="middle"
|
|
184
185
|
dominant-baseline="central"
|
|
185
186
|
>
|
|
186
|
-
{{ resolveYAxisLabel(track.series) }}
|
|
187
|
+
{{ track.series ? resolveYAxisLabel(track.series) : '' }}
|
|
187
188
|
</text>
|
|
188
189
|
</g>
|
|
189
190
|
|
|
@@ -144,6 +144,55 @@ describe('WaveformChart', () => {
|
|
|
144
144
|
expect(wrapper.get('.ant-pagination-next').classes()).toContain('ant-pagination-disabled')
|
|
145
145
|
})
|
|
146
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
|
+
|
|
147
196
|
it('overlays series with the same track ID without changing the next frame', async () => {
|
|
148
197
|
const wrapper = await mountSizedChart(
|
|
149
198
|
{
|
|
@@ -0,0 +1,261 @@
|
|
|
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
|
+
|
|
7
|
+
describe('WaveformChart track order', () => {
|
|
8
|
+
const points = (offset: number) => ({
|
|
9
|
+
kind: 'points' as const,
|
|
10
|
+
points: [
|
|
11
|
+
{ x: 0, y: offset },
|
|
12
|
+
{ x: 1, y: offset + 1 },
|
|
13
|
+
],
|
|
14
|
+
})
|
|
15
|
+
const orderedSeries = (trackIds: string[]) => ({
|
|
16
|
+
kind: 'series' as const,
|
|
17
|
+
series: trackIds.map((trackId, index) => ({
|
|
18
|
+
id: trackId,
|
|
19
|
+
trackId,
|
|
20
|
+
name: trackId,
|
|
21
|
+
data: points(index + 1),
|
|
22
|
+
})),
|
|
23
|
+
})
|
|
24
|
+
const mergedFourTrackSeries = () => ({
|
|
25
|
+
kind: 'series' as const,
|
|
26
|
+
series: [
|
|
27
|
+
{ id: 'frame-1-a', trackId: 'frame-1', name: 'frame-1-a', data: points(1) },
|
|
28
|
+
{ id: 'frame-1-b', trackId: 'frame-1', name: 'frame-1-b', data: points(2) },
|
|
29
|
+
{ id: 'frame-3', trackId: 'frame-3', name: 'frame-3', data: points(3) },
|
|
30
|
+
{ id: 'frame-4', trackId: 'frame-4', name: 'frame-4', data: points(4) },
|
|
31
|
+
],
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('keeps a merged source slot empty without adding legend or tooltip data', async () => {
|
|
35
|
+
const wrapper = await mountSizedChart(
|
|
36
|
+
{
|
|
37
|
+
kind: 'series',
|
|
38
|
+
series: [
|
|
39
|
+
{
|
|
40
|
+
id: 'frame-1-a',
|
|
41
|
+
trackId: 'frame-1',
|
|
42
|
+
name: '合并前通道',
|
|
43
|
+
data: {
|
|
44
|
+
kind: 'points',
|
|
45
|
+
points: [
|
|
46
|
+
{ x: 0, y: 1 },
|
|
47
|
+
{ x: 1, y: 2 },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'frame-1-b',
|
|
53
|
+
trackId: 'frame-1',
|
|
54
|
+
name: '合并后通道',
|
|
55
|
+
data: {
|
|
56
|
+
kind: 'points',
|
|
57
|
+
points: [
|
|
58
|
+
{ x: 0, y: 3 },
|
|
59
|
+
{ x: 1, y: 4 },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'frame-3',
|
|
65
|
+
trackId: 'frame-3',
|
|
66
|
+
name: '后续通道',
|
|
67
|
+
data: {
|
|
68
|
+
kind: 'points',
|
|
69
|
+
points: [
|
|
70
|
+
{ x: 0, y: 5 },
|
|
71
|
+
{ x: 1, y: 6 },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
displayMode: 'separated',
|
|
79
|
+
grid: { rowCount: 3, trackOrder: ['frame-1', 'frame-2', 'frame-3'] },
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
const trackIds = () =>
|
|
83
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id'))
|
|
84
|
+
|
|
85
|
+
expect(trackIds()).toEqual(['frame-1', 'frame-2', 'frame-3'])
|
|
86
|
+
expect(wrapper.findAll('.waveform-chart__track--empty')).toHaveLength(1)
|
|
87
|
+
expect(
|
|
88
|
+
wrapper.findAll('.waveform-chart__line').map((line) => line.attributes('data-series-id')),
|
|
89
|
+
).toEqual(['frame-1-a', 'frame-1-b', 'frame-3'])
|
|
90
|
+
expect(wrapper.findAll('.waveform-chart__legend')).toHaveLength(1)
|
|
91
|
+
|
|
92
|
+
const overlay = wrapper.get('.waveform-chart__overlay--shared')
|
|
93
|
+
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
94
|
+
value: () => ({ left: 0, top: 0, width: 712, height: 290 }),
|
|
95
|
+
})
|
|
96
|
+
overlay.element.dispatchEvent(
|
|
97
|
+
new MouseEvent('pointermove', { clientX: 356, clientY: 150, bubbles: true }),
|
|
98
|
+
)
|
|
99
|
+
flushAnimationFrames()
|
|
100
|
+
await flushPromises()
|
|
101
|
+
|
|
102
|
+
expect(wrapper.findAll('.waveform-chart__tooltip-series')).toHaveLength(3)
|
|
103
|
+
expect(wrapper.get('.waveform-chart__tooltip').text()).not.toContain('frame-2')
|
|
104
|
+
expect(wrapper.findAll('.waveform-chart__crosshair line')).toHaveLength(2)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('appends data tracks absent from trackOrder in input order', async () => {
|
|
108
|
+
const wrapper = await mountSizedChart(
|
|
109
|
+
{
|
|
110
|
+
kind: 'series',
|
|
111
|
+
series: [
|
|
112
|
+
{
|
|
113
|
+
id: 'later-a',
|
|
114
|
+
trackId: 'later-a',
|
|
115
|
+
name: 'later-a',
|
|
116
|
+
data: {
|
|
117
|
+
kind: 'points',
|
|
118
|
+
points: [
|
|
119
|
+
{ x: 0, y: 1 },
|
|
120
|
+
{ x: 1, y: 2 },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'frame-1',
|
|
126
|
+
trackId: 'frame-1',
|
|
127
|
+
name: 'frame-1',
|
|
128
|
+
data: {
|
|
129
|
+
kind: 'points',
|
|
130
|
+
points: [
|
|
131
|
+
{ x: 0, y: 3 },
|
|
132
|
+
{ x: 1, y: 4 },
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: 'later-b',
|
|
138
|
+
trackId: 'later-b',
|
|
139
|
+
name: 'later-b',
|
|
140
|
+
data: {
|
|
141
|
+
kind: 'points',
|
|
142
|
+
points: [
|
|
143
|
+
{ x: 0, y: 5 },
|
|
144
|
+
{ x: 1, y: 6 },
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
{ grid: { rowCount: 2, columnCount: 2, trackOrder: ['frame-2', 'frame-1'] } },
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
expect(
|
|
154
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id')),
|
|
155
|
+
).toEqual(['frame-2', 'frame-1', 'later-a', 'later-b'])
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it.each(['independent', 'separated', 'compact'] as const)(
|
|
159
|
+
'reclaims merged empty slots in %s mode when incomplete rows fill',
|
|
160
|
+
async (displayMode) => {
|
|
161
|
+
const wrapper = await mountSizedChart(mergedFourTrackSeries(), {
|
|
162
|
+
displayMode,
|
|
163
|
+
grid: {
|
|
164
|
+
rowCount: 4,
|
|
165
|
+
columnCount: 1,
|
|
166
|
+
fillIncompleteLastRow: true,
|
|
167
|
+
trackOrder: ['frame-1', 'frame-2', 'frame-3', 'frame-4'],
|
|
168
|
+
},
|
|
169
|
+
})
|
|
170
|
+
const tracks = wrapper.findAll('.waveform-chart__track')
|
|
171
|
+
const heights = tracks.map((track) => Number(track.attributes('data-track-height')))
|
|
172
|
+
|
|
173
|
+
expect(tracks.map((track) => track.attributes('data-track-id'))).toEqual([
|
|
174
|
+
'frame-1',
|
|
175
|
+
'frame-3',
|
|
176
|
+
'frame-4',
|
|
177
|
+
])
|
|
178
|
+
expect(wrapper.findAll('.waveform-chart__track--empty')).toHaveLength(0)
|
|
179
|
+
expect(wrapper.findAll('.waveform-chart__line')).toHaveLength(4)
|
|
180
|
+
expect(heights[0]).toBeCloseTo(heights[1] ?? Number.NaN)
|
|
181
|
+
expect(heights[1]).toBeCloseTo(heights[2] ?? Number.NaN)
|
|
182
|
+
expect(wrapper.findAll('.waveform-chart__legend')).toHaveLength(1)
|
|
183
|
+
expect(wrapper.get('.waveform-chart__legend').text()).not.toContain('frame-2')
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
it('reclaims only the current page without pulling tracks from the next page', async () => {
|
|
188
|
+
const wrapper = await mountSizedChart(
|
|
189
|
+
orderedSeries(['frame-1', 'frame-3', 'frame-4', 'frame-5', 'frame-6', 'frame-7', 'frame-8']),
|
|
190
|
+
{
|
|
191
|
+
grid: {
|
|
192
|
+
rowCount: 4,
|
|
193
|
+
columnCount: 1,
|
|
194
|
+
fillIncompleteLastRow: true,
|
|
195
|
+
trackOrder: [
|
|
196
|
+
'frame-1',
|
|
197
|
+
'frame-2',
|
|
198
|
+
'frame-3',
|
|
199
|
+
'frame-4',
|
|
200
|
+
'frame-5',
|
|
201
|
+
'frame-6',
|
|
202
|
+
'frame-7',
|
|
203
|
+
'frame-8',
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
const trackIds = () =>
|
|
209
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id'))
|
|
210
|
+
|
|
211
|
+
expect(trackIds()).toEqual(['frame-1', 'frame-3', 'frame-4'])
|
|
212
|
+
await wrapper.get('.ant-pagination-next button').trigger('click')
|
|
213
|
+
expect(trackIds()).toEqual(['frame-5', 'frame-6', 'frame-7', 'frame-8'])
|
|
214
|
+
expect(wrapper.emitted('page-change')?.at(-1)).toEqual([2, 2])
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('retains ordered empty slots when incomplete rows do not fill', async () => {
|
|
218
|
+
const wrapper = await mountSizedChart(orderedSeries(['frame-1', 'frame-3', 'frame-4']), {
|
|
219
|
+
grid: {
|
|
220
|
+
rowCount: 4,
|
|
221
|
+
columnCount: 1,
|
|
222
|
+
fillIncompleteLastRow: false,
|
|
223
|
+
trackOrder: ['frame-1', 'frame-2', 'frame-3', 'frame-4'],
|
|
224
|
+
},
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
expect(
|
|
228
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id')),
|
|
229
|
+
).toEqual(['frame-1', 'frame-2', 'frame-3', 'frame-4'])
|
|
230
|
+
expect(wrapper.findAll('.waveform-chart__track--empty')).toHaveLength(1)
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('keeps an entirely empty page addressable when incomplete rows fill', async () => {
|
|
234
|
+
const wrapper = await mountSizedChart(
|
|
235
|
+
orderedSeries(['frame-1', 'frame-2', 'frame-3', 'frame-4']),
|
|
236
|
+
{
|
|
237
|
+
grid: {
|
|
238
|
+
rowCount: 4,
|
|
239
|
+
columnCount: 1,
|
|
240
|
+
fillIncompleteLastRow: true,
|
|
241
|
+
trackOrder: [
|
|
242
|
+
'frame-1',
|
|
243
|
+
'frame-2',
|
|
244
|
+
'frame-3',
|
|
245
|
+
'frame-4',
|
|
246
|
+
'frame-5',
|
|
247
|
+
'frame-6',
|
|
248
|
+
'frame-7',
|
|
249
|
+
'frame-8',
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
await wrapper.get('.ant-pagination-next button').trigger('click')
|
|
256
|
+
|
|
257
|
+
expect(wrapper.findAll('.waveform-chart__track--empty')).toHaveLength(4)
|
|
258
|
+
expect(wrapper.emitted('page-change')?.at(-1)).toEqual([2, 2])
|
|
259
|
+
expect(wrapper.get('.ant-pagination-item-active').text()).toBe('2')
|
|
260
|
+
})
|
|
261
|
+
})
|
package/src/types/chart.ts
CHANGED
|
@@ -176,6 +176,8 @@ export interface WaveformAxesOptions {
|
|
|
176
176
|
lineVisible?: boolean
|
|
177
177
|
/** Target total number of equal Y-axis ticks, including endpoints. Defaults to 5. */
|
|
178
178
|
splitNumber?: number
|
|
179
|
+
/** Expands Y-axis domains to equal, human-friendly intervals. Defaults to true. */
|
|
180
|
+
nice?: boolean
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|