waveform-analysis 0.1.71 → 0.1.73
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 +260 -40
- package/dist/assets/{workerRuntime-o5An0M-W.js → workerRuntime-5p-EI-GL.js} +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.js +3874 -2778
- 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/annotation/useWaveformChartAnnotations.d.ts +0 -1
- 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 +6 -3
- package/dist/types/components/core/niceScale.d.ts +34 -0
- 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 +5 -0
- package/dist/types/components/core/useWaveformChartController.d.ts +24 -6
- package/dist/types/components/core/useWaveformChartLifecycle.d.ts +2 -2
- package/dist/types/components/core/useWaveformData.d.ts +2 -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/useExtremaTickViewport.d.ts +5 -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 +1 -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/data/sx2Channel.d.ts +10 -0
- package/dist/types/demo/DemoYAxisPaddingControls.vue.d.ts +11 -0
- package/dist/types/demo/types.d.ts +7 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/types/chart.d.ts +32 -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 +61 -14
- package/src/components/WaveformChart.css +10 -1
- package/src/components/WaveformChart.vue +6 -0
- package/src/components/WaveformChartView.vue +27 -26
- package/src/components/annotation/WaveformAnnotationLayer.vue +6 -1
- package/src/components/annotation/useWaveformChartAnnotations.ts +7 -18
- package/src/components/controls/WaveformToolbar.vue +247 -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 +49 -36
- package/src/components/core/niceScale.ts +151 -0
- package/src/components/core/trackLayoutBuilder.ts +41 -17
- package/src/components/core/trackPagination.ts +3 -3
- package/src/components/core/types.ts +5 -0
- package/src/components/core/useWaveformChartController.ts +94 -3
- package/src/components/core/useWaveformChartLifecycle.ts +11 -111
- package/src/components/core/useWaveformData.ts +4 -0
- package/src/components/core/useWaveformLayout.ts +25 -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 +11 -9
- package/src/components/core/yAxisPadding.ts +60 -0
- package/src/components/core/yAxisTitleLayout.ts +11 -12
- package/src/components/interaction/useExtremaTickViewport.ts +43 -0
- package/src/components/interaction/useWaveformViewport.ts +11 -2
- package/src/components/rendering/WaveformTrack.css +1 -2
- package/src/components/rendering/WaveformTrack.vue +5 -12
- package/src/components/rendering/WaveformTrackAxes.vue +66 -19
- package/src/components/rendering/WaveformTrackBackdrop.vue +8 -3
- package/src/components/rendering/compactFrame.ts +31 -0
- package/src/components/rendering/yAxisTickVisibility.ts +156 -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 +67 -2
- package/src/data/sx2Channel.ts +315 -0
- 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 +53 -0
- package/src/demo/embedBridge.ts +85 -0
- package/src/demo/types.ts +7 -0
- package/src/index.ts +19 -0
- package/src/types/chart.ts +34 -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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 类型定义统一导出
|
|
3
3
|
*/
|
|
4
|
-
export type { WaveformPoint, WaveformDisplayMode, WaveformUnitDisplayMode, WaveformLayoutPreset, WaveformOverlayMode, WaveformInteractionMode, WaveformXDomainStrategy, WaveformZoomIntentPayload, WaveformZoomEndPayload, WaveformPanEndPayload, WaveformZoomResetPayload, WaveformAnnotationStyle, WaveformAnnotation, WaveformSamplingMode, WaveformSamplingStrategy, WaveformSamplingOptions, WaveformSamplingBackend, WaveformSamplingDiagnostics, WaveformSamplingError, WaveformRenderingOptions, WaveformPlotMargin, WaveformTitleTextStyle, WaveformTitleOptions, WaveformLegendPosition, WaveformLegendOrientation, WaveformLegendOptions, WaveformFrameStyle, WaveformXAxisLabelKind, WaveformXAxisLabelFormatterContext, WaveformXAxisLabelFormatter, WaveformAxesOptions, WaveformZeroLineOptions, } from './chart';
|
|
4
|
+
export type { WaveformPoint, WaveformDisplayMode, WaveformUnitDisplayMode, WaveformLayoutPreset, WaveformOverlayMode, WaveformInteractionMode, WaveformXDomainStrategy, WaveformZoomIntentPayload, WaveformZoomEndPayload, WaveformPanEndPayload, WaveformZoomResetPayload, WaveformAnnotationStyle, WaveformAnnotation, WaveformSamplingMode, WaveformSamplingStrategy, WaveformSamplingOptions, WaveformSamplingBackend, WaveformSamplingDiagnostics, WaveformSamplingError, WaveformRenderingOptions, WaveformPlotMargin, WaveformTitleTextStyle, WaveformTitleOptions, WaveformLegendPosition, WaveformLegendOrientation, WaveformLegendOptions, WaveformFrameStyle, WaveformXAxisLabelKind, WaveformXAxisLabelFormatterContext, WaveformXAxisLabelFormatter, WaveformAxesOptions, WaveformYAxisLabelTextStyle, WaveformZeroLineOptions, } from './chart';
|
|
5
5
|
export type { SingleWaveformData, WaveformLineType, WaveformLineStyle, WaveformPointType, WaveformErrorBarOptions, ResolvedWaveformErrorBarOptions, WaveformTypedValues, TypedSampleData, TypedPointData, WaveformSeries, WaveformData, NormalizedWaveformSeries, } from './data';
|
|
6
|
+
export type { WaveformToolbarItem, WaveformToolbarOptions, WaveformControlTarget, WaveformControlAction, WaveformCommandMetadata, WaveformTargetStatus, WaveformViewportSnapshot, WaveformTargetResult, WaveformControlResult, WaveformControlState, WaveformImageExportOptions, WaveformImageExportErrorCode, WaveformImageExportError, WaveformChartHandle, } from './controls';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waveform-analysis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.73",
|
|
4
4
|
"main": "./dist/index.cjs",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -55,20 +55,21 @@
|
|
|
55
55
|
"scripts": {
|
|
56
56
|
"dev": "vite",
|
|
57
57
|
"build": "pnpm typecheck && pnpm build:lib && pnpm build:types && pnpm build:demo",
|
|
58
|
-
"build:wasm": "
|
|
58
|
+
"build:wasm": "node scripts/prepare-wasm.mjs --force",
|
|
59
59
|
"build:lib": "vite build --config vite.lib.config.ts",
|
|
60
60
|
"build:types": "node scripts/clean-types.mjs && vue-tsc -p tsconfig.lib.json && node scripts/prepare-package-types.mjs",
|
|
61
61
|
"build:demo": "vite build",
|
|
62
62
|
"preview": "vite preview --outDir dist-demo",
|
|
63
|
-
"typecheck": "pnpm
|
|
63
|
+
"typecheck": "pnpm prepare:wasm && vue-tsc -b",
|
|
64
64
|
"check:file-length": "node scripts/check-file-length.mjs",
|
|
65
65
|
"lint": "eslint . --max-warnings=0",
|
|
66
66
|
"lint:oxlint": "oxlint . --deny-warnings",
|
|
67
67
|
"lint:all": "pnpm lint:oxlint && pnpm lint",
|
|
68
68
|
"format": "prettier --write .",
|
|
69
69
|
"format:check": "prettier --check .",
|
|
70
|
-
"test": "pnpm
|
|
71
|
-
"test:coverage": "pnpm
|
|
72
|
-
"test:package": "node scripts/test-package.mjs"
|
|
70
|
+
"test": "pnpm prepare:wasm && vitest run",
|
|
71
|
+
"test:coverage": "pnpm prepare:wasm && vitest run --coverage",
|
|
72
|
+
"test:package": "node scripts/test-package.mjs",
|
|
73
|
+
"prepare:wasm": "node scripts/prepare-wasm.mjs"
|
|
73
74
|
}
|
|
74
75
|
}
|
package/src/App.vue
CHANGED
|
@@ -26,11 +26,23 @@ import DemoControlPanel from './demo/DemoControlPanel.vue'
|
|
|
26
26
|
import type { DemoChartModel, DemoControlPanelModel } from './demo/types'
|
|
27
27
|
import { useDemoXAxisLabelControls } from './demo/useDemoXAxisLabelControls'
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
const
|
|
29
|
+
const demoPreset = new URLSearchParams(window.location.search).get('demo')
|
|
30
|
+
const compactNineDemo = demoPreset === 'compact-nine'
|
|
31
|
+
const compactFourteenDemo = demoPreset === 'compact-fourteen'
|
|
32
|
+
const fullChartData = createSimulatedWaveformData(compactFourteenDemo ? 14 : undefined)
|
|
33
|
+
if (compactNineDemo && fullChartData.kind === 'series') {
|
|
34
|
+
const trackIds = [...new Set(fullChartData.series.map((series) => series.trackId ?? series.id))]
|
|
35
|
+
const demoTrackIds = new Set(trackIds.slice(0, 9))
|
|
36
|
+
fullChartData.series = fullChartData.series.filter((series) =>
|
|
37
|
+
demoTrackIds.has(series.trackId ?? series.id),
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
const displayMode = ref<WaveformDisplayMode>(
|
|
41
|
+
compactNineDemo || compactFourteenDemo ? 'compact' : 'independent',
|
|
42
|
+
)
|
|
31
43
|
const overlayMode = ref<WaveformOverlayMode>('single-axis')
|
|
32
|
-
const rowCount = ref(4)
|
|
33
|
-
const columnCount = ref(1)
|
|
44
|
+
const rowCount = ref(compactNineDemo ? 5 : 4)
|
|
45
|
+
const columnCount = ref(compactNineDemo || compactFourteenDemo ? 2 : 1)
|
|
34
46
|
const frameBorderColor = ref('#1f2937')
|
|
35
47
|
const frameBorderWidth = ref(2)
|
|
36
48
|
const frameBorderStyle = ref<NonNullable<WaveformFrameStyle['borderStyle']>>('solid')
|
|
@@ -42,6 +54,11 @@ const verticalGridVisible = ref(true)
|
|
|
42
54
|
const verticalGridColor = ref('#dfe5ef')
|
|
43
55
|
const xAxisLineVisible = ref(false)
|
|
44
56
|
const yAxisLineVisible = ref(false)
|
|
57
|
+
const upperPaddingEnabled = ref(true)
|
|
58
|
+
const lowerPaddingEnabled = ref(true)
|
|
59
|
+
const extremaTicksVisible = ref(true)
|
|
60
|
+
const upperPaddingPercent = ref(10)
|
|
61
|
+
const lowerPaddingPercent = ref(10)
|
|
45
62
|
const { controlModel: xAxisLabelControlModel, xAxisLabelFormatter } = useDemoXAxisLabelControls()
|
|
46
63
|
const annotations = ref<WaveformAnnotation[]>([])
|
|
47
64
|
const annotationsVisible = ref(true)
|
|
@@ -49,13 +66,14 @@ const cleanView = ref(false)
|
|
|
49
66
|
const presentationMode = ref(false)
|
|
50
67
|
const showTooltip = ref(true)
|
|
51
68
|
const integerZoom = ref(true)
|
|
52
|
-
const plotMarginTop = ref(
|
|
53
|
-
const plotMarginBottom = ref(
|
|
69
|
+
const plotMarginTop = ref(10)
|
|
70
|
+
const plotMarginBottom = ref(44)
|
|
54
71
|
const zeroLineVisible = ref(true)
|
|
55
72
|
const zeroLineColor = ref('#ff0000')
|
|
56
73
|
const zeroLineWidth = ref(1)
|
|
57
74
|
const zeroLineOpacity = ref(0.5)
|
|
58
75
|
const zeroLineDash = ref('6 4')
|
|
76
|
+
const toolbarVisible = ref(true)
|
|
59
77
|
const interactionMode = ref<WaveformInteractionMode>('zoom')
|
|
60
78
|
const legendPosition = ref<WaveformLegendPosition>('top-right')
|
|
61
79
|
const legendOrientation = ref<WaveformLegendOrientation>('auto')
|
|
@@ -65,10 +83,10 @@ const titleVisible = ref(true)
|
|
|
65
83
|
const titleText = ref('模拟波形分析')
|
|
66
84
|
const titleAlign = ref<NonNullable<WaveformTitleOptions['align']>>('center')
|
|
67
85
|
const titleFontFamily = ref('"Microsoft YaHei", "微软雅黑", sans-serif')
|
|
68
|
-
const titleFontSize = ref(
|
|
86
|
+
const titleFontSize = ref(18)
|
|
69
87
|
const titleRotation = ref(0)
|
|
70
88
|
const titleColor = ref('#1f2937')
|
|
71
|
-
const titleBold = ref(
|
|
89
|
+
const titleBold = ref(true)
|
|
72
90
|
const titleItalic = ref(false)
|
|
73
91
|
const titleUnderline = ref(false)
|
|
74
92
|
const controlsOpen = ref(false)
|
|
@@ -123,7 +141,14 @@ const axes = computed<WaveformAxesOptions>(() => ({
|
|
|
123
141
|
lineVisible: xAxisLineVisible.value,
|
|
124
142
|
...(xAxisLabelFormatter.value ? { labelFormatter: xAxisLabelFormatter.value } : {}),
|
|
125
143
|
},
|
|
126
|
-
y: {
|
|
144
|
+
y: {
|
|
145
|
+
lineVisible: yAxisLineVisible.value,
|
|
146
|
+
upperPaddingEnabled: upperPaddingEnabled.value,
|
|
147
|
+
lowerPaddingEnabled: lowerPaddingEnabled.value,
|
|
148
|
+
extremaTicksVisible: extremaTicksVisible.value,
|
|
149
|
+
upperPaddingRatio: upperPaddingPercent.value / 100,
|
|
150
|
+
lowerPaddingRatio: lowerPaddingPercent.value / 100,
|
|
151
|
+
},
|
|
127
152
|
}))
|
|
128
153
|
const zeroLine = computed<WaveformZeroLineOptions>(() => ({
|
|
129
154
|
visible: zeroLineVisible.value,
|
|
@@ -243,7 +268,17 @@ function mergeIndependentWindow(
|
|
|
243
268
|
}
|
|
244
269
|
}
|
|
245
270
|
|
|
271
|
+
let pendingCommandId: string | undefined
|
|
272
|
+
let pendingPayloads: WaveformZoomEndPayload[] = []
|
|
246
273
|
async function handleZoomEnd(payload: WaveformZoomEndPayload) {
|
|
274
|
+
if (payload.action === 'fit') return
|
|
275
|
+
if (payload.commandId && payload.commandId === pendingCommandId) {
|
|
276
|
+
pendingPayloads.push(payload)
|
|
277
|
+
return
|
|
278
|
+
}
|
|
279
|
+
pendingCommandId = payload.commandId
|
|
280
|
+
const batch = [payload]
|
|
281
|
+
pendingPayloads = batch
|
|
247
282
|
// Demo-only sequence number cancellation. Production code should use AbortController
|
|
248
283
|
// to cancel in-flight requests when a newer zoom gesture arrives.
|
|
249
284
|
const requestSequence = ++zoomRequestSequence
|
|
@@ -252,11 +287,16 @@ async function handleZoomEnd(payload: WaveformZoomEndPayload) {
|
|
|
252
287
|
|
|
253
288
|
// Demo-only stand-in for the backend response. Production code should replace this
|
|
254
289
|
// with a request using payload.start/payload.end and the optional channel metadata.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
290
|
+
let nextData = chartData.value
|
|
291
|
+
batch.forEach((item) => {
|
|
292
|
+
const responseData = filterWaveformData(fullChartData, item.start, item.end)
|
|
293
|
+
nextData =
|
|
294
|
+
item.trackIndex !== undefined && item.seriesIds?.length
|
|
295
|
+
? mergeIndependentWindow(nextData, responseData, item.seriesIds)
|
|
296
|
+
: responseData
|
|
297
|
+
})
|
|
298
|
+
chartData.value = nextData
|
|
299
|
+
pendingCommandId = undefined
|
|
260
300
|
}
|
|
261
301
|
|
|
262
302
|
function resetWaveformViewport() {
|
|
@@ -297,6 +337,7 @@ onMounted(() => window.addEventListener('keydown', handleWindowKeydown))
|
|
|
297
337
|
onBeforeUnmount(() => window.removeEventListener('keydown', handleWindowKeydown))
|
|
298
338
|
|
|
299
339
|
const controlPanelModel = reactive({
|
|
340
|
+
toolbarVisible,
|
|
300
341
|
controlsOpen,
|
|
301
342
|
displayMode,
|
|
302
343
|
overlayMode,
|
|
@@ -324,6 +365,11 @@ const controlPanelModel = reactive({
|
|
|
324
365
|
verticalGridColor,
|
|
325
366
|
xAxisLineVisible,
|
|
326
367
|
yAxisLineVisible,
|
|
368
|
+
upperPaddingEnabled,
|
|
369
|
+
lowerPaddingEnabled,
|
|
370
|
+
extremaTicksVisible,
|
|
371
|
+
upperPaddingPercent,
|
|
372
|
+
lowerPaddingPercent,
|
|
327
373
|
...xAxisLabelControlModel,
|
|
328
374
|
frameBorderColor,
|
|
329
375
|
frameBackgroundColor,
|
|
@@ -354,6 +400,7 @@ const controlPanelModel = reactive({
|
|
|
354
400
|
}) satisfies DemoControlPanelModel
|
|
355
401
|
|
|
356
402
|
const chartModel = reactive({
|
|
403
|
+
toolbarVisible,
|
|
357
404
|
data: displayChartData,
|
|
358
405
|
initialXDomain,
|
|
359
406
|
displayMode,
|
|
@@ -117,8 +117,17 @@
|
|
|
117
117
|
font-size: 12px;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
.waveform-chart--interaction-pan:not(.waveform-chart--presentation) .waveform-chart__overlay {
|
|
121
|
+
cursor: grab;
|
|
122
|
+
}
|
|
123
|
+
.waveform-chart--interaction-pan.waveform-chart--panning .waveform-chart__overlay {
|
|
124
|
+
cursor: grabbing;
|
|
125
|
+
}
|
|
126
|
+
.waveform-chart--interaction-none .waveform-chart__overlay {
|
|
127
|
+
cursor: default;
|
|
128
|
+
}
|
|
129
|
+
|
|
120
130
|
.waveform-chart--edge-compact .waveform-chart__x-label {
|
|
121
|
-
font-size: 18px;
|
|
122
131
|
font-weight: 600;
|
|
123
132
|
}
|
|
124
133
|
|
|
@@ -38,6 +38,12 @@ const emit = defineEmits<WaveformChartEmit>()
|
|
|
38
38
|
const controller = useWaveformChartController(props as ResolvedWaveformChartProps, emit)
|
|
39
39
|
|
|
40
40
|
defineExpose({
|
|
41
|
+
exportImage: controller.exportImage,
|
|
42
|
+
zoomIn: controller.zoomIn,
|
|
43
|
+
zoomOut: controller.zoomOut,
|
|
44
|
+
fitToData: controller.fitToData,
|
|
45
|
+
setInteractionMode: controller.setInteractionMode,
|
|
46
|
+
getControlState: controller.getControlState,
|
|
41
47
|
resetViewport: controller.resetViewport,
|
|
42
48
|
setViewportDomain: controller.setViewportDomain,
|
|
43
49
|
})
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import WaveformToolbar from './controls/WaveformToolbar.vue'
|
|
2
3
|
import { Pagination } from 'ant-design-vue'
|
|
3
|
-
import { toRefs } from 'vue'
|
|
4
|
+
import { computed, toRefs } from 'vue'
|
|
4
5
|
|
|
5
6
|
import { WaveformAnnotationContextMenu, WaveformAnnotationLayer } from './annotation'
|
|
6
7
|
import WaveformAnnotationEditor from './annotation/WaveformAnnotationEditor.vue'
|
|
7
8
|
import type { WaveformChartController } from './core/useWaveformChartController'
|
|
8
|
-
import type { TrackLayout } from './core/types'
|
|
9
9
|
import { WaveformHoverHost } from './interaction'
|
|
10
10
|
import { WaveformHoverLayer, WaveformLegend, WaveformTrack } from './rendering'
|
|
11
|
+
import { compactFramePath } from './rendering/compactFrame'
|
|
11
12
|
|
|
12
13
|
const props = defineProps<{ controller: WaveformChartController }>()
|
|
14
|
+
const compactFrameInset = computed(() => {
|
|
15
|
+
const width = props.controller.frameStyle?.borderWidth
|
|
16
|
+
return props.controller.isEdgeCompact
|
|
17
|
+
? (typeof width === 'number' && Number.isFinite(width) && width >= 0 ? width : 1) / 2
|
|
18
|
+
: 0
|
|
19
|
+
})
|
|
13
20
|
const {
|
|
14
21
|
displayMode,
|
|
15
22
|
activeInteractionMode,
|
|
@@ -55,7 +62,6 @@ const {
|
|
|
55
62
|
cancelViewportDrag,
|
|
56
63
|
handlePointerLeave,
|
|
57
64
|
handleAnnotationClick,
|
|
58
|
-
handleAnnotationContextMenu,
|
|
59
65
|
resolveFrameNumber,
|
|
60
66
|
frameStyle,
|
|
61
67
|
axes,
|
|
@@ -111,21 +117,6 @@ function handleChartPointerLeave() {
|
|
|
111
117
|
pointerInsideChart.value = false
|
|
112
118
|
handlePointerLeave.value()
|
|
113
119
|
}
|
|
114
|
-
|
|
115
|
-
function sharesFrameTop(track: TrackLayout): boolean {
|
|
116
|
-
return (
|
|
117
|
-
displayMode.value === 'compact' &&
|
|
118
|
-
trackLayouts.value.some(
|
|
119
|
-
(above) =>
|
|
120
|
-
!above.isEmpty &&
|
|
121
|
-
above !== track &&
|
|
122
|
-
above.column === track.column &&
|
|
123
|
-
Math.abs(above.left - track.left) < 1e-6 &&
|
|
124
|
-
Math.abs(above.width - track.width) < 1e-6 &&
|
|
125
|
-
Math.abs(above.top + above.height - track.top) < 1e-6,
|
|
126
|
-
)
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
120
|
</script>
|
|
130
121
|
|
|
131
122
|
<template>
|
|
@@ -205,7 +196,7 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
205
196
|
|
|
206
197
|
<g :transform="`translate(${resolvedChartLeftMargin}, ${chartTopMargin})`">
|
|
207
198
|
<g
|
|
208
|
-
v-if="displayMode !== 'compact' && !isCleanView"
|
|
199
|
+
v-if="displayMode !== 'compact' && !hasWaveformData && !isCleanView"
|
|
209
200
|
class="waveform-chart__grid-slots"
|
|
210
201
|
aria-hidden="true"
|
|
211
202
|
>
|
|
@@ -238,7 +229,6 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
238
229
|
@pointercancel="cancelViewportDrag"
|
|
239
230
|
@pointerleave="handlePointerLeave"
|
|
240
231
|
@click="handleAnnotationClick"
|
|
241
|
-
@contextmenu="handleAnnotationContextMenu"
|
|
242
232
|
/>
|
|
243
233
|
|
|
244
234
|
<!-- 轨道渲染 -->
|
|
@@ -246,21 +236,28 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
246
236
|
v-for="track in trackLayouts"
|
|
247
237
|
:key="`${track.index}-${track.id}`"
|
|
248
238
|
:track="track"
|
|
239
|
+
:frame-path="
|
|
240
|
+
displayMode === 'compact'
|
|
241
|
+
? compactFramePath(track, trackLayouts, compactFrameInset)
|
|
242
|
+
: undefined
|
|
243
|
+
"
|
|
249
244
|
:clip-path-id="clipPathId"
|
|
250
245
|
:inner-width="innerWidth"
|
|
251
246
|
:zoomable="zoomable"
|
|
252
247
|
:interactive="!isPresentationMode"
|
|
253
248
|
:display-mode="displayMode"
|
|
254
249
|
:interaction-mode="activeInteractionMode"
|
|
255
|
-
:frame-number="
|
|
250
|
+
:frame-number="
|
|
251
|
+
resolveFrameNumber(track.id, (currentPage - 1) * getPageSize(gridOptions) + track.index)
|
|
252
|
+
"
|
|
256
253
|
:frame-style="frameStyle"
|
|
257
254
|
:axes="axes"
|
|
258
255
|
:show-axis-units="unitDisplayMode === 'axis'"
|
|
259
|
-
:show-label-units="
|
|
256
|
+
:show-label-units="
|
|
257
|
+
unitDisplayMode === 'channel-label-or-legend' || unitDisplayMode === 'channel-label'
|
|
258
|
+
"
|
|
260
259
|
:hide-y-axis-titles="hideYAxisTitles"
|
|
261
|
-
:contain-y-axis-endpoints="isEdgeCompact"
|
|
262
260
|
:contain-frame-stroke="isEdgeCompact"
|
|
263
|
-
:omit-frame-top="sharesFrameTop(track)"
|
|
264
261
|
:clean-view="isCleanView"
|
|
265
262
|
:zero-line="resolvedZeroLine"
|
|
266
263
|
:time-unit="timeUnit"
|
|
@@ -271,7 +268,6 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
271
268
|
@pointer-cancel="cancelViewportDrag"
|
|
272
269
|
@pointer-leave="handlePointerLeave"
|
|
273
270
|
@click="handleAnnotationClick($event, track.index)"
|
|
274
|
-
@contextmenu="handleAnnotationContextMenu($event, track.index)"
|
|
275
271
|
/>
|
|
276
272
|
|
|
277
273
|
<WaveformHoverLayer
|
|
@@ -292,10 +288,12 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
292
288
|
/>
|
|
293
289
|
|
|
294
290
|
<WaveformAnnotationLayer
|
|
291
|
+
:cancel-key="activeInteractionMode"
|
|
292
|
+
:data-version="controller.data"
|
|
295
293
|
v-if="!isCleanView"
|
|
296
294
|
:annotations="renderedAnnotations"
|
|
297
295
|
:visible="annotationsVisible"
|
|
298
|
-
:interactive="!isPresentationMode"
|
|
296
|
+
:interactive="!isPresentationMode && activeInteractionMode !== 'none'"
|
|
299
297
|
@contextmenu="handleExistingAnnotationContextMenu"
|
|
300
298
|
@drag-start="beginAnnotationDrag"
|
|
301
299
|
@move="handleAnnotationMove"
|
|
@@ -331,6 +329,7 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
331
329
|
<text
|
|
332
330
|
v-if="resolvedXLabel && !isCleanView"
|
|
333
331
|
class="waveform-chart__label waveform-chart__x-label"
|
|
332
|
+
:style="isEdgeCompact ? { fontSize: titleTextStyle.fontSize } : undefined"
|
|
334
333
|
:x="plotCenterX"
|
|
335
334
|
:y="xAxisTitleY"
|
|
336
335
|
text-anchor="middle"
|
|
@@ -349,6 +348,8 @@ function sharesFrameTop(track: TrackLayout): boolean {
|
|
|
349
348
|
</text>
|
|
350
349
|
</svg>
|
|
351
350
|
|
|
351
|
+
<WaveformToolbar :controller="controller" />
|
|
352
|
+
|
|
352
353
|
<Pagination
|
|
353
354
|
v-if="paginationVisible"
|
|
354
355
|
class="waveform-chart__pagination"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, watch } from 'vue'
|
|
2
|
+
import { computed, ref, watch, onBeforeUnmount } from 'vue'
|
|
3
3
|
|
|
4
4
|
import type { RenderedAnnotation } from './types'
|
|
5
5
|
import { ANNOTATION_TEXT_FONT, ANNOTATION_TEXT_LINE_HEIGHT } from './markup'
|
|
@@ -8,6 +8,8 @@ interface Props {
|
|
|
8
8
|
annotations: RenderedAnnotation[]
|
|
9
9
|
visible: boolean
|
|
10
10
|
interactive?: boolean
|
|
11
|
+
cancelKey?: string
|
|
12
|
+
dataVersion?: unknown
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -211,6 +213,9 @@ watch(
|
|
|
211
213
|
},
|
|
212
214
|
)
|
|
213
215
|
|
|
216
|
+
watch([() => props.cancelKey, () => props.dataVersion, () => props.visible], cancelActiveDrag)
|
|
217
|
+
onBeforeUnmount(cancelActiveDrag)
|
|
218
|
+
|
|
214
219
|
function handleContextMenu(annotationId: string, event: MouseEvent) {
|
|
215
220
|
if (!props.interactive) return
|
|
216
221
|
event.preventDefault()
|
|
@@ -257,17 +257,21 @@ export function useWaveformChartAnnotations(context: AnnotationContext) {
|
|
|
257
257
|
if (
|
|
258
258
|
isPresentationMode.value ||
|
|
259
259
|
!props.annotationsVisible ||
|
|
260
|
+
event.button !== 0 ||
|
|
260
261
|
activeInteractionMode.value !== 'annotation'
|
|
261
262
|
) {
|
|
262
263
|
return
|
|
263
264
|
}
|
|
264
265
|
const candidateContext = resolveAnnotationCandidates(event, trackIndex)
|
|
265
|
-
if (!candidateContext) return
|
|
266
|
+
if (!candidateContext || !candidateContext.candidates.length) return
|
|
266
267
|
const nearby = nearbyCandidates(candidateContext.candidates)
|
|
267
|
-
if (!nearby.length) return
|
|
268
268
|
event.preventDefault()
|
|
269
269
|
event.stopPropagation()
|
|
270
|
-
beginCreate(
|
|
270
|
+
beginCreate(
|
|
271
|
+
nearby[0] ?? candidateContext.candidates[0],
|
|
272
|
+
candidateContext.editorAnchor,
|
|
273
|
+
candidateContext.candidates,
|
|
274
|
+
)
|
|
271
275
|
}
|
|
272
276
|
|
|
273
277
|
function handleNativeContextMenu(event: MouseEvent) {
|
|
@@ -281,20 +285,6 @@ export function useWaveformChartAnnotations(context: AnnotationContext) {
|
|
|
281
285
|
event.preventDefault()
|
|
282
286
|
}
|
|
283
287
|
|
|
284
|
-
function handleAnnotationContextMenu(event: MouseEvent, trackIndex?: number) {
|
|
285
|
-
if (isPresentationMode.value || !props.annotationsVisible) return
|
|
286
|
-
event.preventDefault()
|
|
287
|
-
event.stopPropagation()
|
|
288
|
-
const candidateContext = resolveAnnotationCandidates(event, trackIndex)
|
|
289
|
-
if (!candidateContext || !candidateContext.candidates.length) return
|
|
290
|
-
const nearby = nearbyCandidates(candidateContext.candidates)
|
|
291
|
-
beginCreate(
|
|
292
|
-
nearby[0] ?? candidateContext.candidates[0],
|
|
293
|
-
candidateContext.editorAnchor,
|
|
294
|
-
candidateContext.candidates,
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
288
|
function handleExistingAnnotationContextMenu(annotationId: string, event: MouseEvent) {
|
|
299
289
|
if (isPresentationMode.value || !props.annotationsVisible || !container.value) return
|
|
300
290
|
editorSeriesOptions.value = []
|
|
@@ -387,7 +377,6 @@ export function useWaveformChartAnnotations(context: AnnotationContext) {
|
|
|
387
377
|
resolveTrackAtPointer,
|
|
388
378
|
handleAnnotationClick,
|
|
389
379
|
handleNativeContextMenu,
|
|
390
|
-
handleAnnotationContextMenu,
|
|
391
380
|
handleExistingAnnotationContextMenu,
|
|
392
381
|
handleAnnotationMove,
|
|
393
382
|
editContextAnnotation,
|