waveform-analysis 0.1.57 → 0.1.58
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 +3 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +359 -348
- package/dist/types/components/core/grid.d.ts +3 -0
- package/dist/types/components/core/trackPagination.d.ts +4 -0
- package/dist/types/components/core/useWaveformChartController.d.ts +3 -1
- package/dist/types/components/core/useWaveformLayout.d.ts +2 -1
- package/dist/types/components/core/waveformChartTypes.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/WaveformChartView.vue +3 -3
- package/src/components/core/grid.test.ts +3 -0
- package/src/components/core/grid.ts +4 -0
- package/src/components/core/trackPagination.ts +40 -0
- package/src/components/core/useWaveformLayout.ts +12 -9
- package/src/components/core/waveformChartTypes.ts +2 -0
- package/src/components/waveformChartCases/trackOrder.test.ts +62 -0
|
@@ -9,6 +9,8 @@ export interface WaveformGridOptions {
|
|
|
9
9
|
fillIncompleteLastRow?: boolean;
|
|
10
10
|
/** Stable grid slots. Empty IDs remain as empty chart frames and keep their page position. */
|
|
11
11
|
trackOrder?: string[];
|
|
12
|
+
/** Omits ordered tracks without waveform series from layout and pagination. */
|
|
13
|
+
hideEmptyTracks?: boolean;
|
|
12
14
|
trackLines?: WaveformGridTrackLines;
|
|
13
15
|
}
|
|
14
16
|
export interface WaveformGridLineOptions {
|
|
@@ -32,6 +34,7 @@ export interface NormalizedWaveformGridOptions {
|
|
|
32
34
|
showPagination: boolean;
|
|
33
35
|
fillIncompleteLastRow: boolean;
|
|
34
36
|
trackOrder?: string[];
|
|
37
|
+
hideEmptyTracks?: boolean;
|
|
35
38
|
trackLines: Record<string, NormalizedWaveformGridLineOptions>;
|
|
36
39
|
}
|
|
37
40
|
export interface GridCellGeometry {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DisplayTrack } from './types';
|
|
2
|
+
export declare const resolvePageableTracks: (tracks: DisplayTrack[], hideEmptyTracks?: boolean) => DisplayTrack[];
|
|
3
|
+
export declare const resolveTrackFrameNumber: (frameNumber: string | number | undefined, frameNumbers: Record<string, string | number> | undefined, trackCount: number, trackIndex: number, trackId: string) => string | number | undefined;
|
|
4
|
+
export declare const createFrameNumberResolver: (getFrameNumber: () => string | number | undefined, getFrameNumbers: () => Record<string, string | number> | undefined, getTracks: () => DisplayTrack[]) => (trackId: string) => string | number | undefined;
|
|
@@ -246,6 +246,7 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
|
|
|
246
246
|
confirmAnnotation: (annotation: import("..").WaveformAnnotation) => void;
|
|
247
247
|
chartSeries: import("./types").DisplaySeries[];
|
|
248
248
|
chartTracks: import("./types").DisplayTrack[];
|
|
249
|
+
pageableTracks: import("./types").DisplayTrack[];
|
|
249
250
|
renderingOptions: import("../..").ResolvedWaveformRenderingOptions;
|
|
250
251
|
gridOptions: import("./grid").NormalizedWaveformGridOptions;
|
|
251
252
|
pageCount: number;
|
|
@@ -281,7 +282,7 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
|
|
|
281
282
|
annotationTrackLayouts: import("../annotation").AnnotationTrackLayout[];
|
|
282
283
|
renderedAnnotations: import("../annotation").RenderedAnnotation[];
|
|
283
284
|
editorSeries: import("../annotation").AnnotationSeriesInfo | undefined;
|
|
284
|
-
resolveFrameNumber: (
|
|
285
|
+
resolveFrameNumber: (trackId: string) => string | number | undefined;
|
|
285
286
|
fixedWidth: number | undefined;
|
|
286
287
|
fixedHeight: number | undefined;
|
|
287
288
|
chartWidth: number;
|
|
@@ -341,6 +342,7 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
|
|
|
341
342
|
yDomains?: Record<string, [number, number]> | undefined;
|
|
342
343
|
timeUnit: "s" | "ms";
|
|
343
344
|
frameNumber?: string | number | undefined;
|
|
345
|
+
frameNumbers?: Record<string, string | number> | undefined;
|
|
344
346
|
frameStyle?: import("..").WaveformFrameStyle | undefined;
|
|
345
347
|
axes?: import("..").WaveformAxesOptions | undefined;
|
|
346
348
|
annotations: import("..").WaveformAnnotation[];
|
|
@@ -23,6 +23,7 @@ interface LayoutContext {
|
|
|
23
23
|
export declare function useWaveformLayout(context: LayoutContext): {
|
|
24
24
|
chartSeries: ComputedRef<DisplaySeries[]>;
|
|
25
25
|
chartTracks: ComputedRef<DisplayTrack[]>;
|
|
26
|
+
pageableTracks: ComputedRef<DisplayTrack[]>;
|
|
26
27
|
renderingOptions: ComputedRef<import("../..").ResolvedWaveformRenderingOptions>;
|
|
27
28
|
gridOptions: ComputedRef<import("./grid").NormalizedWaveformGridOptions>;
|
|
28
29
|
pageCount: ComputedRef<number>;
|
|
@@ -58,6 +59,6 @@ export declare function useWaveformLayout(context: LayoutContext): {
|
|
|
58
59
|
annotationTrackLayouts: ComputedRef<AnnotationTrackLayout[]>;
|
|
59
60
|
renderedAnnotations: ComputedRef<import("../annotation").RenderedAnnotation[]>;
|
|
60
61
|
editorSeries: ComputedRef<AnnotationSeriesInfo | undefined>;
|
|
61
|
-
resolveFrameNumber: (
|
|
62
|
+
resolveFrameNumber: (trackId: string) => string | number | undefined;
|
|
62
63
|
};
|
|
63
64
|
export {};
|
|
@@ -22,6 +22,8 @@ export interface WaveformChartProps {
|
|
|
22
22
|
yDomains?: Record<string, [number, number]>;
|
|
23
23
|
timeUnit?: 's' | 'ms';
|
|
24
24
|
frameNumber?: string | number;
|
|
25
|
+
/** Per-track frame watermark overrides, keyed by stable trackId. */
|
|
26
|
+
frameNumbers?: Record<string, string | number>;
|
|
25
27
|
frameStyle?: WaveformFrameStyle;
|
|
26
28
|
axes?: WaveformAxesOptions;
|
|
27
29
|
annotations?: WaveformAnnotation[];
|
package/package.json
CHANGED
|
@@ -80,7 +80,7 @@ const {
|
|
|
80
80
|
pageCount,
|
|
81
81
|
currentPage,
|
|
82
82
|
getPageSize,
|
|
83
|
-
|
|
83
|
+
pageableTracks,
|
|
84
84
|
goToPage,
|
|
85
85
|
annotationInteraction,
|
|
86
86
|
editorDraft,
|
|
@@ -230,7 +230,7 @@ function handleChartPointerLeave() {
|
|
|
230
230
|
:interactive="!isPresentationMode"
|
|
231
231
|
:display-mode="displayMode"
|
|
232
232
|
:interaction-mode="activeInteractionMode"
|
|
233
|
-
:frame-number="resolveFrameNumber(track.
|
|
233
|
+
:frame-number="resolveFrameNumber(track.id)"
|
|
234
234
|
:frame-style="frameStyle"
|
|
235
235
|
:axes="axes"
|
|
236
236
|
:clean-view="isCleanView"
|
|
@@ -326,7 +326,7 @@ function handleChartPointerLeave() {
|
|
|
326
326
|
aria-label="波形分页"
|
|
327
327
|
:current="currentPage"
|
|
328
328
|
:page-size="getPageSize(gridOptions)"
|
|
329
|
-
:total="
|
|
329
|
+
:total="pageableTracks.length"
|
|
330
330
|
:show-size-changer="false"
|
|
331
331
|
:show-quick-jumper="false"
|
|
332
332
|
@change="goToPage"
|
|
@@ -17,6 +17,7 @@ describe('waveform grid helpers', () => {
|
|
|
17
17
|
showPagination: true,
|
|
18
18
|
fillIncompleteLastRow: false,
|
|
19
19
|
trackOrder: [],
|
|
20
|
+
hideEmptyTracks: false,
|
|
20
21
|
trackLines: {},
|
|
21
22
|
})
|
|
22
23
|
expect(normalizeGridOptions({ rowCount: 0, columnCount: 99 })).toEqual({
|
|
@@ -25,8 +26,10 @@ describe('waveform grid helpers', () => {
|
|
|
25
26
|
showPagination: true,
|
|
26
27
|
fillIncompleteLastRow: false,
|
|
27
28
|
trackOrder: [],
|
|
29
|
+
hideEmptyTracks: false,
|
|
28
30
|
trackLines: {},
|
|
29
31
|
})
|
|
32
|
+
expect(normalizeGridOptions({ hideEmptyTracks: true }).hideEmptyTracks).toBe(true)
|
|
30
33
|
})
|
|
31
34
|
|
|
32
35
|
it('normalizes track order by trimming, dropping blanks, and removing duplicates', () => {
|
|
@@ -11,6 +11,8 @@ export interface WaveformGridOptions {
|
|
|
11
11
|
fillIncompleteLastRow?: boolean
|
|
12
12
|
/** Stable grid slots. Empty IDs remain as empty chart frames and keep their page position. */
|
|
13
13
|
trackOrder?: string[]
|
|
14
|
+
/** Omits ordered tracks without waveform series from layout and pagination. */
|
|
15
|
+
hideEmptyTracks?: boolean
|
|
14
16
|
trackLines?: WaveformGridTrackLines
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -38,6 +40,7 @@ export interface NormalizedWaveformGridOptions {
|
|
|
38
40
|
showPagination: boolean
|
|
39
41
|
fillIncompleteLastRow: boolean
|
|
40
42
|
trackOrder?: string[]
|
|
43
|
+
hideEmptyTracks?: boolean
|
|
41
44
|
trackLines: Record<string, NormalizedWaveformGridLineOptions>
|
|
42
45
|
}
|
|
43
46
|
|
|
@@ -95,6 +98,7 @@ export function normalizeGridOptions(options?: WaveformGridOptions): NormalizedW
|
|
|
95
98
|
showPagination: options?.showPagination ?? true,
|
|
96
99
|
fillIncompleteLastRow: options?.fillIncompleteLastRow ?? false,
|
|
97
100
|
trackOrder: normalizeTrackOrder(options?.trackOrder),
|
|
101
|
+
hideEmptyTracks: options?.hideEmptyTracks ?? false,
|
|
98
102
|
trackLines,
|
|
99
103
|
}
|
|
100
104
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DisplayTrack } from './types'
|
|
2
|
+
|
|
3
|
+
export const resolvePageableTracks = (
|
|
4
|
+
tracks: DisplayTrack[],
|
|
5
|
+
hideEmptyTracks?: boolean,
|
|
6
|
+
): DisplayTrack[] => (hideEmptyTracks ? tracks.filter((track) => track.series.length > 0) : tracks)
|
|
7
|
+
|
|
8
|
+
export const resolveTrackFrameNumber = (
|
|
9
|
+
frameNumber: string | number | undefined,
|
|
10
|
+
frameNumbers: Record<string, string | number> | undefined,
|
|
11
|
+
trackCount: number,
|
|
12
|
+
trackIndex: number,
|
|
13
|
+
trackId: string,
|
|
14
|
+
): string | number | undefined => {
|
|
15
|
+
const mappedFrameNumber = frameNumbers?.[trackId]
|
|
16
|
+
if (mappedFrameNumber !== undefined) return mappedFrameNumber
|
|
17
|
+
if (frameNumber === undefined) return undefined
|
|
18
|
+
if (trackCount === 1) return frameNumber
|
|
19
|
+
return typeof frameNumber === 'number'
|
|
20
|
+
? frameNumber + trackIndex
|
|
21
|
+
: `${frameNumber}-${trackIndex + 1}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const createFrameNumberResolver =
|
|
25
|
+
(
|
|
26
|
+
getFrameNumber: () => string | number | undefined,
|
|
27
|
+
getFrameNumbers: () => Record<string, string | number> | undefined,
|
|
28
|
+
getTracks: () => DisplayTrack[],
|
|
29
|
+
) =>
|
|
30
|
+
(trackId: string): string | number | undefined => {
|
|
31
|
+
const tracks = getTracks()
|
|
32
|
+
const trackIndex = tracks.findIndex((track) => track.id === trackId)
|
|
33
|
+
return resolveTrackFrameNumber(
|
|
34
|
+
getFrameNumber(),
|
|
35
|
+
getFrameNumbers(),
|
|
36
|
+
tracks.length,
|
|
37
|
+
trackIndex >= 0 ? trackIndex : 0,
|
|
38
|
+
trackId,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
resolveYAxisSeriesGroups,
|
|
32
32
|
} from './layout'
|
|
33
33
|
import type { DisplaySeries, DisplayTrack, TrackLayout } from './types'
|
|
34
|
+
import { createFrameNumberResolver, resolvePageableTracks } from './trackPagination'
|
|
34
35
|
import type { PreparedWaveformSeries } from './useWaveformData'
|
|
35
36
|
import type { ResolvedWaveformChartProps } from './waveformChartTypes'
|
|
36
37
|
import { applyXDomainStrategy } from './xDomain'
|
|
@@ -107,9 +108,12 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
107
108
|
})
|
|
108
109
|
})
|
|
109
110
|
const renderingOptions = computed(() => resolveWaveformRenderingOptions(props.rendering))
|
|
110
|
-
const
|
|
111
|
+
const pageableTracks = computed(() =>
|
|
112
|
+
resolvePageableTracks(chartTracks.value, gridOptions.value.hideEmptyTracks),
|
|
113
|
+
)
|
|
114
|
+
const pageCount = computed(() => getPageCount(pageableTracks.value.length, gridOptions.value))
|
|
111
115
|
const pagedTracks = computed(() =>
|
|
112
|
-
paginateSeries(
|
|
116
|
+
paginateSeries(pageableTracks.value, currentPage.value, gridOptions.value),
|
|
113
117
|
)
|
|
114
118
|
const layoutTracks = computed(() => {
|
|
115
119
|
const tracksWithSeries = pagedTracks.value.filter((track) => track.series.length > 0)
|
|
@@ -357,16 +361,15 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
357
361
|
}
|
|
358
362
|
: undefined
|
|
359
363
|
})
|
|
360
|
-
const resolveFrameNumber = (
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
: `${props.frameNumber}-${trackIndex + 1}`
|
|
366
|
-
}
|
|
364
|
+
const resolveFrameNumber = createFrameNumberResolver(
|
|
365
|
+
() => props.frameNumber,
|
|
366
|
+
() => props.frameNumbers,
|
|
367
|
+
() => chartTracks.value,
|
|
368
|
+
)
|
|
367
369
|
return {
|
|
368
370
|
chartSeries,
|
|
369
371
|
chartTracks,
|
|
372
|
+
pageableTracks,
|
|
370
373
|
renderingOptions,
|
|
371
374
|
gridOptions,
|
|
372
375
|
pageCount,
|
|
@@ -43,6 +43,8 @@ export interface WaveformChartProps {
|
|
|
43
43
|
yDomains?: Record<string, [number, number]>
|
|
44
44
|
timeUnit?: 's' | 'ms'
|
|
45
45
|
frameNumber?: string | number
|
|
46
|
+
/** Per-track frame watermark overrides, keyed by stable trackId. */
|
|
47
|
+
frameNumbers?: Record<string, string | number>
|
|
46
48
|
frameStyle?: WaveformFrameStyle
|
|
47
49
|
axes?: WaveformAxesOptions
|
|
48
50
|
annotations?: WaveformAnnotation[]
|
|
@@ -104,6 +104,68 @@ describe('WaveformChart track order', () => {
|
|
|
104
104
|
expect(wrapper.findAll('.waveform-chart__crosshair line')).toHaveLength(2)
|
|
105
105
|
})
|
|
106
106
|
|
|
107
|
+
it('keeps incremental watermarks stable when empty ordered tracks are hidden', async () => {
|
|
108
|
+
const wrapper = await mountSizedChart(mergedFourTrackSeries(), {
|
|
109
|
+
frameNumber: 1,
|
|
110
|
+
grid: {
|
|
111
|
+
rowCount: 2,
|
|
112
|
+
columnCount: 1,
|
|
113
|
+
hideEmptyTracks: true,
|
|
114
|
+
trackOrder: ['frame-1', 'frame-2', 'frame-3', 'frame-4'],
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
expect(
|
|
119
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id')),
|
|
120
|
+
).toEqual(['frame-1', 'frame-3'])
|
|
121
|
+
expect(
|
|
122
|
+
wrapper.findAll('.waveform-chart__watermark').map((watermark) => watermark.text()),
|
|
123
|
+
).toEqual(['1', '3'])
|
|
124
|
+
|
|
125
|
+
await wrapper.get('.ant-pagination-next button').trigger('click')
|
|
126
|
+
|
|
127
|
+
expect(
|
|
128
|
+
wrapper.findAll('.waveform-chart__track').map((track) => track.attributes('data-track-id')),
|
|
129
|
+
).toEqual(['frame-4'])
|
|
130
|
+
expect(
|
|
131
|
+
wrapper.findAll('.waveform-chart__watermark').map((watermark) => watermark.text()),
|
|
132
|
+
).toEqual(['4'])
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('uses stable track IDs for explicit frame watermark overrides', async () => {
|
|
136
|
+
const wrapper = await mountSizedChart(mergedFourTrackSeries(), {
|
|
137
|
+
frameNumber: 1,
|
|
138
|
+
frameNumbers: { 'frame-1': 'A', 'frame-3': 'C', 'frame-4': 'D' },
|
|
139
|
+
grid: {
|
|
140
|
+
rowCount: 2,
|
|
141
|
+
columnCount: 1,
|
|
142
|
+
hideEmptyTracks: true,
|
|
143
|
+
trackOrder: ['frame-1', 'frame-2', 'frame-3', 'frame-4'],
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
expect(
|
|
148
|
+
wrapper.findAll('.waveform-chart__watermark').map((watermark) => watermark.text()),
|
|
149
|
+
).toEqual(['A', 'C'])
|
|
150
|
+
|
|
151
|
+
await wrapper.get('.ant-pagination-next button').trigger('click')
|
|
152
|
+
|
|
153
|
+
expect(
|
|
154
|
+
wrapper.findAll('.waveform-chart__watermark').map((watermark) => watermark.text()),
|
|
155
|
+
).toEqual(['D'])
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('keeps the existing incremental watermark fallback when frame mappings are absent', async () => {
|
|
159
|
+
const wrapper = await mountSizedChart(orderedSeries(['frame-1', 'frame-2']), {
|
|
160
|
+
frameNumber: 7,
|
|
161
|
+
grid: { rowCount: 2, columnCount: 1 },
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect(
|
|
165
|
+
wrapper.findAll('.waveform-chart__watermark').map((watermark) => watermark.text()),
|
|
166
|
+
).toEqual(['7', '8'])
|
|
167
|
+
})
|
|
168
|
+
|
|
107
169
|
it('appends data tracks absent from trackOrder in input order', async () => {
|
|
108
170
|
const wrapper = await mountSizedChart(
|
|
109
171
|
{
|