waveform-analysis 0.1.70 → 0.1.72
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 +244 -45
- package/dist/assets/workerRuntime-5p-EI-GL.js +1 -0
- package/dist/index.cjs +2 -1
- package/dist/index.js +2924 -1915
- package/dist/style.css +1 -1
- package/dist/types/components/WaveformChart.vue.d.ts +24 -6
- package/dist/types/components/annotation/WaveformAnnotationLayer.vue.d.ts +2 -0
- package/dist/types/components/controls/WaveformToolbar.vue.d.ts +7 -0
- package/dist/types/components/controls/chartExportOptions.d.ts +5 -0
- package/dist/types/components/controls/chartSnapshot.d.ts +2 -0
- package/dist/types/components/controls/snapshotTitle.d.ts +2 -0
- package/dist/types/components/controls/toolbarRegistry.d.ts +21 -0
- package/dist/types/components/controls/useChartCommands.d.ts +42 -0
- package/dist/types/components/controls/useChartImageExport.d.ts +17 -0
- package/dist/types/components/controls/useControlMode.d.ts +8 -0
- package/dist/types/components/core/latestTaskScheduler.d.ts +1 -1
- package/dist/types/components/core/layout.d.ts +5 -3
- package/dist/types/components/core/niceScale.d.ts +34 -0
- package/dist/types/components/core/pagination.d.ts +2 -2
- package/dist/types/components/core/trackLayoutBuilder.d.ts +4 -1
- package/dist/types/components/core/trackPagination.d.ts +1 -1
- package/dist/types/components/core/types.d.ts +3 -0
- package/dist/types/components/core/useWaveformChartController.d.ts +24 -5
- package/dist/types/components/core/useWaveformChartLifecycle.d.ts +2 -2
- package/dist/types/components/core/useWaveformData.d.ts +1 -0
- package/dist/types/components/core/useWaveformLayout.d.ts +4 -1
- package/dist/types/components/core/useWaveformMeasurements.d.ts +2 -0
- package/dist/types/components/core/useWaveformRenderSampling.d.ts +1 -0
- package/dist/types/components/core/useWaveformViewportRestore.d.ts +5 -0
- package/dist/types/components/core/waveformChartTypes.d.ts +5 -0
- package/dist/types/components/core/waveformSamplingSession.d.ts +24 -0
- package/dist/types/components/core/yAxisLabelStyle.d.ts +3 -0
- package/dist/types/components/core/yAxisLayoutMetrics.d.ts +2 -1
- package/dist/types/components/core/yAxisPadding.d.ts +7 -0
- package/dist/types/components/core/yAxisTitleLayout.d.ts +2 -0
- package/dist/types/components/interaction/useWaveformViewport.d.ts +1 -0
- package/dist/types/components/rendering/WaveformLegend.vue.d.ts +2 -2
- package/dist/types/components/rendering/WaveformTrack.vue.d.ts +2 -3
- package/dist/types/components/rendering/WaveformTrackAxes.vue.d.ts +0 -1
- package/dist/types/components/rendering/WaveformTrackBackdrop.vue.d.ts +1 -0
- package/dist/types/components/rendering/compactFrame.d.ts +5 -0
- package/dist/types/components/rendering/yAxisTickVisibility.d.ts +11 -0
- package/dist/types/core/lineBoundary.d.ts +4 -0
- package/dist/types/core/rendering.d.ts +4 -0
- package/dist/types/core/renderingStrategies.d.ts +2 -0
- package/dist/types/core/workerSampling/outputBoundaries.d.ts +4 -0
- package/dist/types/data/simulatedWaveforms.d.ts +1 -1
- package/dist/types/demo/DemoYAxisPaddingControls.vue.d.ts +11 -0
- package/dist/types/demo/types.d.ts +6 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/types/chart.d.ts +30 -8
- package/dist/types/types/controls.d.ts +69 -0
- package/dist/types/types/index.d.ts +2 -1
- package/dist/types/utils/formatters.d.ts +1 -0
- package/package.json +7 -6
- package/src/App.vue +58 -14
- package/src/components/WaveformChart.css +10 -1
- package/src/components/WaveformChart.vue +6 -0
- package/src/components/WaveformChartView.vue +27 -23
- package/src/components/annotation/WaveformAnnotationLayer.vue +6 -1
- package/src/components/annotation/useWaveformChartAnnotations.ts +6 -1
- package/src/components/controls/WaveformToolbar.vue +248 -0
- package/src/components/controls/chartExportOptions.ts +32 -0
- package/src/components/controls/chartSnapshot.ts +132 -0
- package/src/components/controls/snapshotTitle.ts +73 -0
- package/src/components/controls/toolbarRegistry.ts +92 -0
- package/src/components/controls/useChartCommands.ts +294 -0
- package/src/components/controls/useChartImageExport.ts +155 -0
- package/src/components/controls/useControlMode.ts +30 -0
- package/src/components/core/latestTaskScheduler.ts +14 -2
- package/src/components/core/layout.ts +35 -34
- package/src/components/core/niceScale.ts +151 -0
- package/src/components/core/pagination.ts +3 -16
- package/src/components/core/trackLayoutBuilder.ts +34 -17
- package/src/components/core/trackPagination.ts +3 -3
- package/src/components/core/types.ts +3 -0
- package/src/components/core/useWaveformChartController.ts +95 -10
- package/src/components/core/useWaveformChartLifecycle.ts +11 -111
- package/src/components/core/useWaveformData.ts +2 -0
- package/src/components/core/useWaveformLayout.ts +17 -5
- package/src/components/core/useWaveformMeasurements.ts +63 -0
- package/src/components/core/useWaveformRenderSampling.ts +80 -59
- package/src/components/core/useWaveformViewportRestore.ts +105 -0
- package/src/components/core/useWaveformYAxisLayout.ts +3 -2
- package/src/components/core/waveformChartTypes.ts +5 -0
- package/src/components/core/waveformSamplingSession.ts +49 -0
- package/src/components/core/workerSamplingClient.ts +38 -6
- package/src/components/core/yAxisLabelStyle.ts +10 -0
- package/src/components/core/yAxisLayoutMetrics.ts +10 -9
- package/src/components/core/yAxisPadding.ts +45 -0
- package/src/components/core/yAxisTitleLayout.ts +11 -12
- package/src/components/interaction/useWaveformViewport.ts +11 -2
- package/src/components/rendering/WaveformTrack.css +1 -2
- package/src/components/rendering/WaveformTrack.vue +4 -12
- package/src/components/rendering/WaveformTrackAxes.vue +48 -19
- package/src/components/rendering/WaveformTrackBackdrop.vue +8 -3
- package/src/components/rendering/compactFrame.ts +31 -0
- package/src/components/rendering/yAxisTickVisibility.ts +95 -0
- package/src/core/lineBoundary.ts +24 -0
- package/src/core/rendering.ts +48 -25
- package/src/core/renderingStrategies.ts +19 -13
- package/src/core/waveformPointSource.ts +23 -1
- package/src/core/workerSampling/outputBoundaries.ts +32 -0
- package/src/core/workerSampling/repository.ts +26 -18
- package/src/core/workerSampling/repositoryDataset.ts +33 -1
- package/src/core/workerSampling/workerRuntime.ts +13 -3
- package/src/data/simulatedWaveforms.ts +57 -2
- package/src/demo/DemoChartHost.vue +5 -1
- package/src/demo/DemoGridFrameControls.vue +2 -0
- package/src/demo/DemoViewControls.vue +5 -2
- package/src/demo/DemoYAxisPaddingControls.vue +46 -0
- package/src/demo/embedBridge.ts +85 -0
- package/src/demo/types.ts +6 -0
- package/src/index.ts +18 -0
- package/src/types/chart.ts +32 -8
- package/src/types/controls.ts +80 -0
- package/src/types/index.ts +18 -0
- package/src/utils/formatters.ts +2 -1
- package/src/views/WasmSamplingDemo.vue +8 -1
- package/dist/assets/workerRuntime-BcYng9TR.js +0 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { withMaximumTick, type YAxisPaddingOptions } from './yAxisPadding'
|
|
2
|
+
import { selectSeriesRenderSourcePoints } from '../../core/rendering'
|
|
3
|
+
import { pointSourceFromPoints } from '../../core/waveformPointSource'
|
|
1
4
|
import {
|
|
2
5
|
curveStep,
|
|
3
6
|
curveStepAfter,
|
|
@@ -8,10 +11,7 @@ import {
|
|
|
8
11
|
type ZoomTransform,
|
|
9
12
|
} from 'd3'
|
|
10
13
|
|
|
11
|
-
import {
|
|
12
|
-
selectSeriesRenderPoints,
|
|
13
|
-
type ResolvedWaveformRenderingOptions,
|
|
14
|
-
} from '../../core/rendering'
|
|
14
|
+
import { type ResolvedWaveformRenderingOptions } from '../../core/rendering'
|
|
15
15
|
import type {
|
|
16
16
|
WaveformDisplayMode,
|
|
17
17
|
WaveformOverlayMode,
|
|
@@ -36,6 +36,7 @@ import type { DisplayTrack, TrackLayout, WaveformYAxisLayout } from './types'
|
|
|
36
36
|
import { applyXDomainStrategy } from './xDomain'
|
|
37
37
|
import { alignLeftYAxisTitles } from './yAxisTitleLayout'
|
|
38
38
|
import { measureYAxisTextWidth } from './yAxisTextWidth'
|
|
39
|
+
import { resolveYAxisLabelBandWidth } from './yAxisLabelStyle'
|
|
39
40
|
import {
|
|
40
41
|
alignIntegerZoomDomain,
|
|
41
42
|
normalizeIntegerZoomDomain,
|
|
@@ -43,7 +44,6 @@ import {
|
|
|
43
44
|
formatIntegerZoomLabel,
|
|
44
45
|
} from '../interaction/integerZoom'
|
|
45
46
|
import {
|
|
46
|
-
Y_AXIS_LABEL_BAND_WIDTH,
|
|
47
47
|
Y_AXIS_LABEL_GAP,
|
|
48
48
|
Y_AXIS_OUTER_PADDING,
|
|
49
49
|
Y_AXIS_RIGHT_LABEL_OFFSET,
|
|
@@ -61,6 +61,7 @@ export interface BuildTrackLayoutsOptions {
|
|
|
61
61
|
overlayMode: WaveformOverlayMode
|
|
62
62
|
independentTransforms: ZoomTransform[]
|
|
63
63
|
sharedZoomDomain: [number, number]
|
|
64
|
+
effectiveXDomains?: Record<string, [number, number]>
|
|
64
65
|
initialXDomain?: [number, number]
|
|
65
66
|
initialXDomains?: Record<string, [number, number]>
|
|
66
67
|
xDomainStrategy?: WaveformXDomainStrategy
|
|
@@ -72,6 +73,7 @@ export interface BuildTrackLayoutsOptions {
|
|
|
72
73
|
xAxisLabelFormatter?: WaveformXAxisLabelFormatter
|
|
73
74
|
yAxisSplitNumber?: number
|
|
74
75
|
yAxisNice?: boolean
|
|
76
|
+
yAxisPadding?: YAxisPaddingOptions
|
|
75
77
|
yAxisUpperPaddingRatio?: number
|
|
76
78
|
rendering: ResolvedWaveformRenderingOptions
|
|
77
79
|
/** Latest sampling result for SVG lines only; source series remain complete for interaction. */
|
|
@@ -80,7 +82,7 @@ export interface BuildTrackLayoutsOptions {
|
|
|
80
82
|
yAxisLabelX: number
|
|
81
83
|
yLabel?: string
|
|
82
84
|
yAxisSlots?: readonly YAxisSlot[]
|
|
83
|
-
|
|
85
|
+
showEmptyTracks: boolean
|
|
84
86
|
useNonEmptyBottomTracks?: boolean
|
|
85
87
|
compactYAxisLayout?: boolean
|
|
86
88
|
showAxisUnits?: boolean
|
|
@@ -91,6 +93,7 @@ function resolveIndependentXDomain(
|
|
|
91
93
|
seriesId: string,
|
|
92
94
|
options: BuildTrackLayoutsOptions,
|
|
93
95
|
): [number, number] {
|
|
96
|
+
if (options.effectiveXDomains?.[track.id]) return options.effectiveXDomains[track.id]
|
|
94
97
|
const strategy = options.xDomainStrategy ?? { type: 'data' }
|
|
95
98
|
const explicitDomain =
|
|
96
99
|
options.initialXDomains?.[track.id] ??
|
|
@@ -115,13 +118,12 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
115
118
|
|
|
116
119
|
const layouts: TrackLayout[] = visibleCells.flatMap((cell, index) => {
|
|
117
120
|
const isEmpty = !cell.series || cell.series.series.length === 0
|
|
118
|
-
if (!cell.series &&
|
|
119
|
-
return []
|
|
121
|
+
if (!cell.series && !options.showEmptyTracks) return []
|
|
120
122
|
const displayTrack: DisplayTrack = cell.series ?? {
|
|
121
123
|
id: `empty-grid-slot-${cell.slotIndex}`,
|
|
122
124
|
series: [],
|
|
123
125
|
visibleSeries: [],
|
|
124
|
-
xDomain:
|
|
126
|
+
xDomain: options.initialXDomain ?? options.sharedZoomDomain,
|
|
125
127
|
yDomain: [0, 1],
|
|
126
128
|
}
|
|
127
129
|
const hasVisibleSeries = !isEmpty && displayTrack.visibleSeries.length > 0
|
|
@@ -145,7 +147,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
145
147
|
options.fixedYDomain,
|
|
146
148
|
options.fixedYDomains,
|
|
147
149
|
options.yDomains,
|
|
148
|
-
options.yAxisUpperPaddingRatio,
|
|
150
|
+
options.yAxisPadding ?? options.yAxisUpperPaddingRatio,
|
|
149
151
|
)
|
|
150
152
|
const sideIndexes = { left: 0, right: 0 }
|
|
151
153
|
const sideOffsets = { left: 0, right: 0 }
|
|
@@ -155,7 +157,13 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
155
157
|
const resolvedTicks = resolveYAxisTicks(group.domain, tickCount, options.yAxisNice !== false)
|
|
156
158
|
const scale = scaleLinear(resolvedTicks.domain, [cell.plotHeight, 0])
|
|
157
159
|
const majorTicks = resolvedTicks.values
|
|
158
|
-
const
|
|
160
|
+
const maximumTick =
|
|
161
|
+
group.maximumTick !== undefined &&
|
|
162
|
+
group.maximumTick >= resolvedTicks.domain[0] &&
|
|
163
|
+
group.maximumTick <= resolvedTicks.domain[1]
|
|
164
|
+
? group.maximumTick
|
|
165
|
+
: undefined
|
|
166
|
+
const tickValues = withMaximumTick(majorTicks, maximumTick)
|
|
159
167
|
const { tickTextWidth } = axisTextMetrics(
|
|
160
168
|
scale.domain() as [number, number],
|
|
161
169
|
false,
|
|
@@ -167,7 +175,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
167
175
|
tickTextWidth +
|
|
168
176
|
Y_AXIS_TICK_PADDING +
|
|
169
177
|
Y_AXIS_LABEL_GAP +
|
|
170
|
-
|
|
178
|
+
resolveYAxisLabelBandWidth(options.yAxisPadding?.labelTextStyle) +
|
|
171
179
|
Y_AXIS_OUTER_PADDING
|
|
172
180
|
const slot = options.yAxisSlots?.find(
|
|
173
181
|
(candidate) => candidate.side === group.side && candidate.sideIndex === sideIndex,
|
|
@@ -178,7 +186,10 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
178
186
|
? -sideOffsets.left
|
|
179
187
|
: cell.width + sideOffsets.right
|
|
180
188
|
const labelDistance =
|
|
181
|
-
tickTextWidth +
|
|
189
|
+
tickTextWidth +
|
|
190
|
+
Y_AXIS_TICK_PADDING +
|
|
191
|
+
Y_AXIS_LABEL_GAP +
|
|
192
|
+
resolveYAxisLabelBandWidth(options.yAxisPadding?.labelTextStyle) / 2
|
|
182
193
|
const labelX =
|
|
183
194
|
(slot
|
|
184
195
|
? (group.side === 'left' ? 0 : cell.width) + slot.labelOffset
|
|
@@ -191,6 +202,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
191
202
|
x,
|
|
192
203
|
labelX,
|
|
193
204
|
scale,
|
|
205
|
+
maximumTick,
|
|
194
206
|
majorTicks,
|
|
195
207
|
minorTicks: buildMinorTicks(majorTicks, 2),
|
|
196
208
|
tickValues,
|
|
@@ -207,7 +219,11 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
207
219
|
)
|
|
208
220
|
const xAxisLabelFormatter =
|
|
209
221
|
options.xAxisLabelFormatter ?? (options.integerZoom ? formatIntegerZoomLabel : undefined)
|
|
210
|
-
const yMajorTicks =
|
|
222
|
+
const yMajorTicks =
|
|
223
|
+
yAxes[0]?.majorTicks ??
|
|
224
|
+
(isEmpty
|
|
225
|
+
? fallbackYScale.ticks(resolveYAxisTickCount(cell.plotHeight, options.yAxisSplitNumber))
|
|
226
|
+
: [])
|
|
211
227
|
const yAxisTickValues = yAxes[0]?.tickValues ?? []
|
|
212
228
|
const domain = xScale.domain() as [number, number]
|
|
213
229
|
const endpointLabels = {
|
|
@@ -225,8 +241,8 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
225
241
|
axis.seriesList.some((series) => series.id === trackSeries.id),
|
|
226
242
|
)
|
|
227
243
|
const seriesYScale = yAxis?.scale ?? yScale
|
|
228
|
-
const renderPoints =
|
|
229
|
-
trackSeries.points,
|
|
244
|
+
const renderPoints = selectSeriesRenderSourcePoints(
|
|
245
|
+
trackSeries.source ?? pointSourceFromPoints(trackSeries.points),
|
|
230
246
|
domain,
|
|
231
247
|
cell.width,
|
|
232
248
|
options.rendering,
|
|
@@ -278,7 +294,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
278
294
|
xAxisLabelFormatter,
|
|
279
295
|
xMinorTicks: buildMinorTicks(xMajorTicks, 3, domain),
|
|
280
296
|
yMajorTicks,
|
|
281
|
-
yMinorTicks: yAxes[0]?.minorTicks ?? [],
|
|
297
|
+
yMinorTicks: yAxes[0]?.minorTicks ?? (isEmpty ? buildMinorTicks(yMajorTicks, 2) : []),
|
|
282
298
|
yAxisTickValues,
|
|
283
299
|
xAxisTickValues,
|
|
284
300
|
endpointLabels,
|
|
@@ -297,6 +313,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
|
|
297
313
|
})
|
|
298
314
|
|
|
299
315
|
alignLeftYAxisTitles(layouts, options.yLabel, {
|
|
316
|
+
labelTextStyle: options.yAxisPadding?.labelTextStyle,
|
|
300
317
|
showUnits: options.showAxisUnits,
|
|
301
318
|
compact: options.compactYAxisLayout,
|
|
302
319
|
measureTextWidth: options.compactYAxisLayout ? measureYAxisTextWidth : undefined,
|
|
@@ -27,14 +27,14 @@ export const createFrameNumberResolver =
|
|
|
27
27
|
getFrameNumbers: () => Record<string, string | number> | undefined,
|
|
28
28
|
getTracks: () => DisplayTrack[],
|
|
29
29
|
) =>
|
|
30
|
-
(trackId: string): string | number | undefined => {
|
|
30
|
+
(trackId: string, slotIndex = 0): string | number | undefined => {
|
|
31
31
|
const tracks = getTracks()
|
|
32
32
|
const trackIndex = tracks.findIndex((track) => track.id === trackId)
|
|
33
33
|
return resolveTrackFrameNumber(
|
|
34
34
|
getFrameNumber(),
|
|
35
35
|
getFrameNumbers(),
|
|
36
|
-
tracks.length,
|
|
37
|
-
trackIndex >= 0 ? trackIndex :
|
|
36
|
+
Math.max(tracks.length, slotIndex + 1),
|
|
37
|
+
trackIndex >= 0 ? trackIndex : slotIndex,
|
|
38
38
|
trackId,
|
|
39
39
|
)
|
|
40
40
|
}
|
|
@@ -27,6 +27,7 @@ export interface DisplaySeries {
|
|
|
27
27
|
points: WaveformPoint[]
|
|
28
28
|
source?: WaveformPointSource
|
|
29
29
|
xDomain: [number, number]
|
|
30
|
+
rawYMaximum?: number
|
|
30
31
|
yDomain: [number, number]
|
|
31
32
|
hasErrorPoints: boolean
|
|
32
33
|
}
|
|
@@ -38,6 +39,7 @@ export interface DisplayTrack {
|
|
|
38
39
|
/** Series currently participating in layout, rendering, and interaction. */
|
|
39
40
|
visibleSeries: DisplaySeries[]
|
|
40
41
|
xDomain: [number, number]
|
|
42
|
+
rawYMaximum?: number
|
|
41
43
|
yDomain: [number, number]
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -51,6 +53,7 @@ export interface TrackSeriesPath {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export interface WaveformYAxisLayout {
|
|
56
|
+
maximumTick?: number
|
|
54
57
|
index: number
|
|
55
58
|
side: 'left' | 'right'
|
|
56
59
|
x: number
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import { chartExportOptions } from '../controls/chartExportOptions'
|
|
2
|
+
import { useChartImageExport } from '../controls/useChartImageExport'
|
|
3
|
+
import { useControlMode } from '../controls/useControlMode'
|
|
4
|
+
import { useChartCommands } from '../controls/useChartCommands'
|
|
1
5
|
import { zoomIdentity, type ZoomTransform } from 'd3'
|
|
2
6
|
import {
|
|
3
7
|
computed,
|
|
4
8
|
reactive,
|
|
9
|
+
nextTick,
|
|
10
|
+
onBeforeUnmount,
|
|
5
11
|
markRaw,
|
|
6
12
|
ref,
|
|
7
13
|
shallowReactive,
|
|
@@ -44,9 +50,15 @@ function assignElement<T extends Element>(
|
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
export function useWaveformChartController(
|
|
47
|
-
|
|
53
|
+
inputProps: ResolvedWaveformChartProps,
|
|
48
54
|
emit: WaveformChartEmit,
|
|
49
55
|
) {
|
|
56
|
+
const mode = useControlMode(inputProps, emit)
|
|
57
|
+
const props = reactive({
|
|
58
|
+
...toRefs(inputProps),
|
|
59
|
+
interactionMode: mode.mode,
|
|
60
|
+
}) as ResolvedWaveformChartProps
|
|
61
|
+
const boundaries = shallowRef<Record<string, [number, number]>>({})
|
|
50
62
|
const container = ref<HTMLDivElement>()
|
|
51
63
|
const svgElement = ref<SVGSVGElement>()
|
|
52
64
|
const titleMeasureElement = ref<HTMLSpanElement>()
|
|
@@ -137,6 +149,7 @@ export function useWaveformChartController(
|
|
|
137
149
|
independentYDomains,
|
|
138
150
|
annotationInteraction: markRaw(annotationInteraction),
|
|
139
151
|
linePointOverrides,
|
|
152
|
+
boundaries,
|
|
140
153
|
})
|
|
141
154
|
const {
|
|
142
155
|
chartSeries,
|
|
@@ -164,7 +177,7 @@ export function useWaveformChartController(
|
|
|
164
177
|
presentation.titleAreaStyle,
|
|
165
178
|
)
|
|
166
179
|
|
|
167
|
-
useWaveformRenderSampling({
|
|
180
|
+
const sampling = useWaveformRenderSampling({
|
|
168
181
|
props,
|
|
169
182
|
emit,
|
|
170
183
|
instanceId: clipPathId,
|
|
@@ -180,13 +193,7 @@ export function useWaveformChartController(
|
|
|
180
193
|
watchEffect(() => {
|
|
181
194
|
paginationBandHeight.value =
|
|
182
195
|
props.layoutPreset === 'edge-compact'
|
|
183
|
-
? resolveCompactPaginationBand(
|
|
184
|
-
paginationVisible.value,
|
|
185
|
-
chartWidth.value,
|
|
186
|
-
pageCount.value,
|
|
187
|
-
resolvedChartLeftMargin.value + innerWidth.value / 2,
|
|
188
|
-
layout.resolvedXLabel.value,
|
|
189
|
-
)
|
|
196
|
+
? resolveCompactPaginationBand(paginationVisible.value)
|
|
190
197
|
: gridOptions.value.showPagination && pageCount.value > 1 && chartWidth.value <= 520
|
|
191
198
|
? 40
|
|
192
199
|
: 0
|
|
@@ -235,6 +242,7 @@ export function useWaveformChartController(
|
|
|
235
242
|
})
|
|
236
243
|
|
|
237
244
|
const viewport = useWaveformViewport({
|
|
245
|
+
clearBoundaries: (index) => commands.clearBoundaries(index),
|
|
238
246
|
props,
|
|
239
247
|
emit,
|
|
240
248
|
selection,
|
|
@@ -278,7 +286,50 @@ export function useWaveformChartController(
|
|
|
278
286
|
resolveTrackAtPointer: annotations.resolveTrackAtPointer,
|
|
279
287
|
})
|
|
280
288
|
|
|
289
|
+
const cancelControls = () => {
|
|
290
|
+
viewport.cancelViewportDrag()
|
|
291
|
+
zoom.cancelPendingZoom()
|
|
292
|
+
hover.clearHover()
|
|
293
|
+
annotations.cancelAnnotation()
|
|
294
|
+
}
|
|
295
|
+
const commands = useChartCommands({
|
|
296
|
+
props,
|
|
297
|
+
emit,
|
|
298
|
+
layout,
|
|
299
|
+
mode,
|
|
300
|
+
boundaries,
|
|
301
|
+
independentTransforms,
|
|
302
|
+
sharedTransform,
|
|
303
|
+
independentYDomains,
|
|
304
|
+
sharedYDomains,
|
|
305
|
+
cancel: cancelControls,
|
|
306
|
+
configure: zoom.configureZoom,
|
|
307
|
+
legacyReset: viewport.resetViewport,
|
|
308
|
+
legacySet: viewport.setViewportDomain,
|
|
309
|
+
})
|
|
310
|
+
watch(
|
|
311
|
+
[mode.mode, () => props.zoomable, () => props.pannable, () => props.annotationsVisible],
|
|
312
|
+
cancelControls,
|
|
313
|
+
{ flush: 'sync' },
|
|
314
|
+
)
|
|
315
|
+
watch([currentPage, () => props.displayMode], () => {
|
|
316
|
+
boundaries.value = {}
|
|
317
|
+
cancelControls()
|
|
318
|
+
})
|
|
319
|
+
watch(
|
|
320
|
+
[
|
|
321
|
+
() => props.initialXDomain,
|
|
322
|
+
() => props.initialXDomains,
|
|
323
|
+
hiddenSeriesIdSet,
|
|
324
|
+
() => props.xDomainStrategy,
|
|
325
|
+
],
|
|
326
|
+
commands.restoreInitialBoundaries,
|
|
327
|
+
{ deep: true },
|
|
328
|
+
)
|
|
329
|
+
onBeforeUnmount(cancelControls)
|
|
330
|
+
|
|
281
331
|
const lifecycle = useWaveformChartLifecycle({
|
|
332
|
+
preserveFullViewport: () => Object.keys(boundaries.value).length > 0,
|
|
282
333
|
props,
|
|
283
334
|
emit,
|
|
284
335
|
container,
|
|
@@ -323,7 +374,39 @@ export function useWaveformChartController(
|
|
|
323
374
|
clearZoomBindings: zoom.clearZoomBindings,
|
|
324
375
|
})
|
|
325
376
|
handleBeforeDataReferenceChange = lifecycle.handleBeforeDataReferenceChange
|
|
326
|
-
handleDataReferenceChange =
|
|
377
|
+
handleDataReferenceChange = () => {
|
|
378
|
+
boundaries.value = {}
|
|
379
|
+
viewport.cancelViewportDrag()
|
|
380
|
+
lifecycle.handleDataReferenceChange()
|
|
381
|
+
void nextTick(zoom.configureZoom)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const imageExport = useChartImageExport({
|
|
385
|
+
container: () => container.value,
|
|
386
|
+
svg: () => svgElement.value,
|
|
387
|
+
size: () => ({
|
|
388
|
+
width: chartWidth.value,
|
|
389
|
+
height: chartHeight.value,
|
|
390
|
+
titleHeight: titleAreaHeight.value,
|
|
391
|
+
}),
|
|
392
|
+
version: () => [
|
|
393
|
+
props.data,
|
|
394
|
+
JSON.stringify({
|
|
395
|
+
...chartExportOptions(props),
|
|
396
|
+
hidden: [...hiddenSeriesIdSet.value],
|
|
397
|
+
width: chartWidth.value,
|
|
398
|
+
height: chartHeight.value,
|
|
399
|
+
titleHeight: titleAreaHeight.value,
|
|
400
|
+
page: currentPage.value,
|
|
401
|
+
shared: sharedTransform.value,
|
|
402
|
+
independent: independentTransforms.value,
|
|
403
|
+
sharedY: sharedYDomains.value,
|
|
404
|
+
independentY: independentYDomains.value,
|
|
405
|
+
boundaries: boundaries.value,
|
|
406
|
+
}),
|
|
407
|
+
],
|
|
408
|
+
ready: sampling.ready,
|
|
409
|
+
})
|
|
327
410
|
|
|
328
411
|
return reactive({
|
|
329
412
|
...toRefs(props),
|
|
@@ -335,6 +418,8 @@ export function useWaveformChartController(
|
|
|
335
418
|
...annotations,
|
|
336
419
|
...viewport,
|
|
337
420
|
...hover,
|
|
421
|
+
...commands,
|
|
422
|
+
...imageExport,
|
|
338
423
|
margin,
|
|
339
424
|
getPageSize,
|
|
340
425
|
currentPage,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useWaveformMeasurements } from './useWaveformMeasurements'
|
|
2
|
+
import { useWaveformViewportRestore } from './useWaveformViewportRestore'
|
|
1
3
|
import { zoomIdentity, type ZoomTransform } from 'd3'
|
|
2
4
|
import {
|
|
3
5
|
nextTick,
|
|
@@ -13,12 +15,10 @@ import type { AnnotationSeriesCandidate, useWaveformAnnotationInteraction } from
|
|
|
13
15
|
import type { NormalizedWaveformGridOptions } from './grid'
|
|
14
16
|
import type { DisplaySeries, DisplayTrack, TrackLayout } from './types'
|
|
15
17
|
import type { ResolvedWaveformChartProps, WaveformChartEmit } from './waveformChartTypes'
|
|
16
|
-
import { transformForDomain } from '../interaction/zoomConstraints'
|
|
17
|
-
import { remotePanBoundary, restoreViewportDomain } from '../interaction/remoteViewport'
|
|
18
18
|
import { isEditableTarget } from '../interaction/interactionTarget'
|
|
19
|
-
import { seriesIdentity } from '../interaction/zoomEventPayload'
|
|
20
19
|
|
|
21
|
-
interface LifecycleContext {
|
|
20
|
+
export interface LifecycleContext {
|
|
21
|
+
preserveFullViewport?: () => boolean
|
|
22
22
|
props: ResolvedWaveformChartProps
|
|
23
23
|
emit: WaveformChartEmit
|
|
24
24
|
container: Ref<HTMLDivElement | undefined>
|
|
@@ -64,19 +64,10 @@ interface LifecycleContext {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
67
|
+
useWaveformMeasurements(context)
|
|
67
68
|
const {
|
|
68
69
|
props,
|
|
69
70
|
emit,
|
|
70
|
-
container,
|
|
71
|
-
titleMeasureElement,
|
|
72
|
-
resizeObserver,
|
|
73
|
-
observedWidth,
|
|
74
|
-
observedHeight,
|
|
75
|
-
measuredTitleWidth,
|
|
76
|
-
measuredTitleHeight,
|
|
77
|
-
resolvedTitleText,
|
|
78
|
-
titleAreaReserved,
|
|
79
|
-
titleMeasureStyle,
|
|
80
71
|
spacePressed,
|
|
81
72
|
pointerInsideChart,
|
|
82
73
|
currentPage,
|
|
@@ -85,18 +76,13 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
85
76
|
gridOptions,
|
|
86
77
|
chartSeries,
|
|
87
78
|
chartTracks,
|
|
88
|
-
trackLayouts,
|
|
89
79
|
innerWidth,
|
|
90
80
|
innerHeight,
|
|
91
|
-
sharedZoomDomain,
|
|
92
|
-
initialXDomain,
|
|
93
|
-
sharedTransform,
|
|
94
81
|
activeInteractionMode,
|
|
95
82
|
hiddenSeriesIdSet,
|
|
96
83
|
internalHiddenSeriesIds,
|
|
97
84
|
independentTransforms,
|
|
98
85
|
independentYDomains,
|
|
99
|
-
resolveInitialTrackDomain,
|
|
100
86
|
annotationInteraction,
|
|
101
87
|
editorSeriesOptions,
|
|
102
88
|
isPresentationMode,
|
|
@@ -110,6 +96,10 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
110
96
|
} = context
|
|
111
97
|
|
|
112
98
|
function handleInteractionKeyDown(event: KeyboardEvent) {
|
|
99
|
+
if (event.key === 'Escape') {
|
|
100
|
+
cancelViewportDrag()
|
|
101
|
+
cancelAnnotation()
|
|
102
|
+
}
|
|
113
103
|
if (
|
|
114
104
|
isPresentationMode.value ||
|
|
115
105
|
event.code !== 'Space' ||
|
|
@@ -142,68 +132,8 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
142
132
|
emit('page-change', nextPage, pageCount.value)
|
|
143
133
|
}
|
|
144
134
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
function handleBeforeDataReferenceChange() {
|
|
149
|
-
if (props.displayMode === 'independent') {
|
|
150
|
-
pendingSharedXDomain = undefined
|
|
151
|
-
pendingIndependentXDomains = new Map(
|
|
152
|
-
trackLayouts.value.flatMap((track) => {
|
|
153
|
-
const current = track.xScale.domain() as [number, number]
|
|
154
|
-
const boundary = resolveInitialTrackDomain(track)
|
|
155
|
-
return remotePanBoundary(props) ||
|
|
156
|
-
current[1] - current[0] < boundary[1] - boundary[0] - 1e-12
|
|
157
|
-
? [[seriesIdentity(track.seriesList.map((series) => series.id)), current]]
|
|
158
|
-
: []
|
|
159
|
-
}),
|
|
160
|
-
)
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
pendingIndependentXDomains = undefined
|
|
164
|
-
const current = sharedZoomDomain.value
|
|
165
|
-
const boundary = initialXDomain.value
|
|
166
|
-
pendingSharedXDomain =
|
|
167
|
-
remotePanBoundary(props) || current[1] - current[0] < boundary[1] - boundary[0] - 1e-12
|
|
168
|
-
? [...current]
|
|
169
|
-
: undefined
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function handleDataReferenceChange() {
|
|
173
|
-
if (props.displayMode === 'independent') {
|
|
174
|
-
const currentTransforms = independentTransforms.value
|
|
175
|
-
independentTransforms.value = chartTracks.value.map(
|
|
176
|
-
(_track, index) => currentTransforms[index] ?? zoomIdentity,
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
clearHover()
|
|
180
|
-
editorSeriesOptions.value = []
|
|
181
|
-
void nextTick(() => {
|
|
182
|
-
if (props.displayMode === 'independent' && pendingIndependentXDomains) {
|
|
183
|
-
const nextTransforms = chartTracks.value.map(() => zoomIdentity)
|
|
184
|
-
trackLayouts.value.forEach((track) => {
|
|
185
|
-
const previousDomain = pendingIndependentXDomains?.get(
|
|
186
|
-
seriesIdentity(track.seriesList.map((series) => series.id)),
|
|
187
|
-
)
|
|
188
|
-
if (!previousDomain) return
|
|
189
|
-
const boundary = resolveInitialTrackDomain(track)
|
|
190
|
-
const domain = restoreViewportDomain(previousDomain, boundary, [track.seriesList], props)
|
|
191
|
-
nextTransforms[track.index] = transformForDomain(domain, boundary, track.width)
|
|
192
|
-
})
|
|
193
|
-
independentTransforms.value = nextTransforms
|
|
194
|
-
pendingIndependentXDomains = undefined
|
|
195
|
-
} else if (props.displayMode !== 'independent' && pendingSharedXDomain) {
|
|
196
|
-
const boundary = initialXDomain.value
|
|
197
|
-
const groups = trackLayouts.value
|
|
198
|
-
.filter((track) => track.hasVisibleSeries)
|
|
199
|
-
.map((track) => track.seriesList)
|
|
200
|
-
const domain = restoreViewportDomain(pendingSharedXDomain, boundary, groups, props)
|
|
201
|
-
sharedTransform.value = transformForDomain(domain, boundary, innerWidth.value)
|
|
202
|
-
pendingSharedXDomain = undefined
|
|
203
|
-
}
|
|
204
|
-
configureZoom()
|
|
205
|
-
})
|
|
206
|
-
}
|
|
135
|
+
const { handleBeforeDataReferenceChange, handleDataReferenceChange } =
|
|
136
|
+
useWaveformViewportRestore(context)
|
|
207
137
|
|
|
208
138
|
watch(
|
|
209
139
|
[
|
|
@@ -347,45 +277,15 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
|
|
347
277
|
{ deep: true },
|
|
348
278
|
)
|
|
349
279
|
|
|
350
|
-
function measureTitle() {
|
|
351
|
-
if (!titleAreaReserved.value || !titleMeasureElement.value) {
|
|
352
|
-
measuredTitleWidth.value = 0
|
|
353
|
-
measuredTitleHeight.value = 0
|
|
354
|
-
return
|
|
355
|
-
}
|
|
356
|
-
const bounds = titleMeasureElement.value.getBoundingClientRect()
|
|
357
|
-
measuredTitleWidth.value = titleMeasureElement.value.scrollWidth || bounds.width
|
|
358
|
-
measuredTitleHeight.value = titleMeasureElement.value.scrollHeight || bounds.height
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
watch(
|
|
362
|
-
[resolvedTitleText, titleAreaReserved, titleMeasureStyle],
|
|
363
|
-
async () => {
|
|
364
|
-
measuredTitleWidth.value = 0
|
|
365
|
-
measuredTitleHeight.value = 0
|
|
366
|
-
await nextTick()
|
|
367
|
-
measureTitle()
|
|
368
|
-
},
|
|
369
|
-
{ immediate: true },
|
|
370
|
-
)
|
|
371
|
-
|
|
372
280
|
onMounted(() => {
|
|
373
281
|
window.addEventListener('keydown', handleInteractionKeyDown)
|
|
374
282
|
window.addEventListener('keyup', handleInteractionKeyUp)
|
|
375
|
-
if (!container.value) return
|
|
376
|
-
resizeObserver.value = new ResizeObserver(([entry]) => {
|
|
377
|
-
observedWidth.value = Math.max(0, entry?.contentRect.width ?? 0)
|
|
378
|
-
observedHeight.value = Math.max(0, entry?.contentRect.height ?? 0)
|
|
379
|
-
void nextTick(measureTitle)
|
|
380
|
-
})
|
|
381
|
-
resizeObserver.value.observe(container.value)
|
|
382
283
|
})
|
|
383
284
|
|
|
384
285
|
onBeforeUnmount(() => {
|
|
385
286
|
window.removeEventListener('keydown', handleInteractionKeyDown)
|
|
386
287
|
window.removeEventListener('keyup', handleInteractionKeyUp)
|
|
387
288
|
cancelPendingHover()
|
|
388
|
-
resizeObserver.value?.disconnect()
|
|
389
289
|
clearZoomBindings()
|
|
390
290
|
editorSeriesOptions.value = []
|
|
391
291
|
})
|
|
@@ -25,6 +25,7 @@ export interface PreparedWaveformSeries {
|
|
|
25
25
|
points: WaveformPoint[]
|
|
26
26
|
source: WaveformPointSource
|
|
27
27
|
xDomain: [number, number]
|
|
28
|
+
rawYMaximum?: number
|
|
28
29
|
yDomain: [number, number]
|
|
29
30
|
hasErrorPoints: boolean
|
|
30
31
|
}
|
|
@@ -48,6 +49,7 @@ export function prepareWaveformSeries(data: WaveformData): PreparedWaveformSerie
|
|
|
48
49
|
? [sourceMetrics.yMinimum, sourceMetrics.yMaximum]
|
|
49
50
|
: [],
|
|
50
51
|
),
|
|
52
|
+
rawYMaximum: Number.isFinite(sourceMetrics.yMaximum) ? sourceMetrics.yMaximum : undefined,
|
|
51
53
|
hasErrorPoints: sourceMetrics.hasErrorPoints,
|
|
52
54
|
}
|
|
53
55
|
})
|
|
@@ -20,6 +20,7 @@ import { resolveViewportYDomains } from './yAxisLayoutMetrics'
|
|
|
20
20
|
import { useWaveformYAxisLayout } from './useWaveformYAxisLayout'
|
|
21
21
|
import type { useWaveformAnnotationInteraction } from '../annotation'
|
|
22
22
|
interface LayoutContext {
|
|
23
|
+
boundaries?: ShallowRef<Record<string, [number, number]>>
|
|
23
24
|
props: ResolvedWaveformChartProps
|
|
24
25
|
preparedSeries: ShallowRef<PreparedWaveformSeries[]>
|
|
25
26
|
currentPage: Ref<number>
|
|
@@ -147,7 +148,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
147
148
|
const hasChartArea = computed(() => innerWidth.value > 0 && innerHeight.value > 0)
|
|
148
149
|
const resolvedXLabel = computed(() => props.xLabel ?? `时间(${props.timeUnit})`)
|
|
149
150
|
const activeInteractionMode = computed(() => props.interactionMode)
|
|
150
|
-
const isZoomMode = computed(() => activeInteractionMode.value
|
|
151
|
+
const isZoomMode = computed(() => activeInteractionMode.value === 'zoom')
|
|
151
152
|
const sharedXDomain = computed(() => {
|
|
152
153
|
const values: number[] = []
|
|
153
154
|
const tracks = chartTracks.value.some((track) => track.visibleSeries.length)
|
|
@@ -158,7 +159,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
158
159
|
})
|
|
159
160
|
return paddedDomain(values)
|
|
160
161
|
})
|
|
161
|
-
const
|
|
162
|
+
const originalXDomain = computed<[number, number]>(() => {
|
|
162
163
|
const domain = props.initialXDomain
|
|
163
164
|
if (
|
|
164
165
|
domain &&
|
|
@@ -180,7 +181,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
180
181
|
props,
|
|
181
182
|
)
|
|
182
183
|
})
|
|
183
|
-
const
|
|
184
|
+
const resolveOriginalTrackDomain = (track: TrackLayout): [number, number] => {
|
|
184
185
|
const configuredDomain =
|
|
185
186
|
props.initialXDomains?.[track.series?.trackId ?? track.series?.id ?? track.id] ??
|
|
186
187
|
(track.series ? props.initialXDomains?.[track.series.id] : undefined) ??
|
|
@@ -210,6 +211,13 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
210
211
|
props,
|
|
211
212
|
)
|
|
212
213
|
}
|
|
214
|
+
const initialXDomain = computed(
|
|
215
|
+
() =>
|
|
216
|
+
(props.displayMode !== 'independent' ? context.boundaries?.value.shared : undefined) ??
|
|
217
|
+
originalXDomain.value,
|
|
218
|
+
)
|
|
219
|
+
const resolveInitialTrackDomain = (track: TrackLayout): [number, number] =>
|
|
220
|
+
context.boundaries?.value[track.id] ?? resolveOriginalTrackDomain(track)
|
|
213
221
|
const sharedZoomDomain = computed(() =>
|
|
214
222
|
normalizeIntegerZoomDomain(
|
|
215
223
|
sharedTransform.value
|
|
@@ -240,6 +248,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
240
248
|
useNonEmptyBottomTracks: props.layoutPreset === 'edge-compact',
|
|
241
249
|
compactYAxisLayout: props.layoutPreset === 'edge-compact',
|
|
242
250
|
showAxisUnits:
|
|
251
|
+
props.unitDisplayMode !== 'channel-label' &&
|
|
243
252
|
props.unitDisplayMode !== 'channel-label-or-legend' &&
|
|
244
253
|
(props.layoutPreset !== 'edge-compact' || props.unitDisplayMode === 'axis'),
|
|
245
254
|
displayMode: props.displayMode,
|
|
@@ -248,6 +257,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
248
257
|
sharedZoomDomain: sharedZoomDomain.value,
|
|
249
258
|
initialXDomain: props.initialXDomain ? initialXDomain.value : undefined,
|
|
250
259
|
initialXDomains: props.initialXDomains,
|
|
260
|
+
effectiveXDomains: context.boundaries?.value,
|
|
251
261
|
xDomainStrategy: props.xDomainStrategy,
|
|
252
262
|
integerZoom: props.integerZoom,
|
|
253
263
|
fixedYDomain: props.yDomain,
|
|
@@ -257,7 +267,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
257
267
|
xAxisLabelFormatter: props.axes?.x?.labelFormatter,
|
|
258
268
|
yAxisSplitNumber: props.axes?.y?.splitNumber,
|
|
259
269
|
yAxisNice: props.axes?.y?.nice,
|
|
260
|
-
|
|
270
|
+
yAxisPadding: props.axes?.y,
|
|
261
271
|
rendering: renderingOptions.value,
|
|
262
272
|
linePointOverrides: linePointOverrides?.value,
|
|
263
273
|
hideSecondaryLabels: isCleanView.value || yAxisLayout.value.hideSecondaryLabels,
|
|
@@ -266,7 +276,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
266
276
|
yAxisSlots.value.slots.find((slot) => slot.side === 'left' && slot.sideIndex === 0)
|
|
267
277
|
?.labelOffset ?? yAxisMetrics.value.labelCenterX,
|
|
268
278
|
yAxisSlots: yAxisSlots.value.slots,
|
|
269
|
-
|
|
279
|
+
showEmptyTracks: hasWaveformData.value,
|
|
270
280
|
}),
|
|
271
281
|
)
|
|
272
282
|
const annotationLayoutsForTrack = (track: TrackLayout): AnnotationTrackLayout[] =>
|
|
@@ -329,6 +339,8 @@ export function useWaveformLayout(context: LayoutContext) {
|
|
|
329
339
|
activeInteractionMode,
|
|
330
340
|
isZoomMode,
|
|
331
341
|
initialXDomain,
|
|
342
|
+
originalXDomain,
|
|
343
|
+
resolveOriginalTrackDomain,
|
|
332
344
|
sharedZoomDomain,
|
|
333
345
|
resolveInitialTrackDomain,
|
|
334
346
|
gridCells,
|