waveform-analysis 0.1.65 → 0.1.67
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 +146 -5
- package/dist/index.cjs +1 -1
- package/dist/index.js +1326 -1118
- package/dist/style.css +1 -1
- package/dist/types/components/WaveformChart.vue.d.ts +7 -2
- package/dist/types/components/core/constants.d.ts +2 -0
- package/dist/types/components/core/grid.d.ts +1 -1
- package/dist/types/components/core/layout.d.ts +2 -2
- package/dist/types/components/core/pagination.d.ts +2 -0
- package/dist/types/components/core/title.d.ts +2 -1
- package/dist/types/components/core/trackLayoutBuilder.d.ts +5 -0
- package/dist/types/components/core/types.d.ts +2 -1
- package/dist/types/components/core/useWaveformChartController.d.ts +9 -0
- package/dist/types/components/core/useWaveformLayout.d.ts +1 -0
- package/dist/types/components/core/useWaveformPresentation.d.ts +3 -0
- package/dist/types/components/core/useWaveformYAxisLayout.d.ts +31 -0
- package/dist/types/components/core/waveformChartTypes.d.ts +11 -2
- package/dist/types/components/core/yAxisLayoutMetrics.d.ts +1 -1
- package/dist/types/components/core/yAxisTitleLayout.d.ts +4 -0
- package/dist/types/components/data/types.d.ts +1 -1
- package/dist/types/components/interaction/integerZoom.d.ts +12 -0
- package/dist/types/components/interaction/interactionTarget.d.ts +1 -0
- package/dist/types/components/interaction/remoteViewport.d.ts +8 -0
- package/dist/types/components/interaction/useWaveformViewport.d.ts +1 -2
- package/dist/types/components/interaction/viewportDomain.d.ts +1 -1
- package/dist/types/components/interaction/viewportPan.d.ts +4 -0
- package/dist/types/components/interaction/zoomConstraints.d.ts +2 -1
- package/dist/types/components/rendering/WaveformLegend.vue.d.ts +2 -0
- package/dist/types/components/rendering/WaveformTrack.vue.d.ts +6 -6
- package/dist/types/components/rendering/WaveformTrackAxes.vue.d.ts +5 -1
- package/dist/types/components/rendering/WaveformTrackBackdrop.vue.d.ts +0 -4
- package/dist/types/components/rendering/WaveformZeroLines.vue.d.ts +12 -0
- package/dist/types/data/recordedDampedWaveform.d.ts +1 -0
- package/dist/types/demo/types.d.ts +3 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/types/chart.d.ts +17 -0
- package/dist/types/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/App.vue +6 -0
- package/src/components/WaveformChart.css +5 -0
- package/src/components/WaveformChart.vue +3 -0
- package/src/components/WaveformChartView.vue +14 -3
- package/src/components/core/constants.ts +2 -0
- package/src/components/core/grid.ts +4 -1
- package/src/components/core/layout.ts +16 -2
- package/src/components/core/pagination.ts +17 -0
- package/src/components/core/title.ts +7 -3
- package/src/components/core/trackLayoutBuilder.ts +39 -59
- package/src/components/core/types.ts +2 -0
- package/src/components/core/useWaveformChartController.ts +17 -1
- package/src/components/core/useWaveformChartLifecycle.ts +11 -17
- package/src/components/core/useWaveformLayout.ts +67 -107
- package/src/components/core/useWaveformPresentation.ts +27 -3
- package/src/components/core/useWaveformYAxisLayout.ts +140 -0
- package/src/components/core/waveformChartTypes.ts +15 -0
- package/src/components/core/yAxisLayoutMetrics.ts +11 -2
- package/src/components/core/yAxisTitleLayout.ts +78 -0
- package/src/components/data/types.ts +3 -0
- package/src/components/interaction/integerZoom.ts +64 -0
- package/src/components/interaction/interactionTarget.ts +10 -0
- package/src/components/interaction/remoteViewport.ts +53 -0
- package/src/components/interaction/useWaveformViewport.ts +16 -58
- package/src/components/interaction/useWaveformZoom.ts +13 -11
- package/src/components/interaction/viewportDomain.ts +11 -3
- package/src/components/interaction/viewportPan.ts +82 -0
- package/src/components/interaction/zoomConstraints.ts +7 -5
- package/src/components/rendering/WaveformLegend.vue +10 -1
- package/src/components/rendering/WaveformTrack.vue +24 -6
- package/src/components/rendering/WaveformTrackAxes.vue +16 -5
- package/src/components/rendering/WaveformTrackBackdrop.vue +2 -34
- package/src/components/rendering/WaveformZeroLines.vue +53 -0
- package/src/data/recordedDampedWaveform.ts +3 -0
- package/src/data/simulatedWaveforms.ts +12 -10
- package/src/demo/DemoChartHost.vue +1 -0
- package/src/demo/DemoGridFrameControls.vue +12 -0
- package/src/demo/DemoViewControls.vue +4 -0
- package/src/demo/types.ts +3 -0
- package/src/index.ts +4 -0
- package/src/styles.css +3 -3
- package/src/types/chart.ts +20 -0
- package/src/types/index.ts +3 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type ZoomTransform } from 'd3';
|
|
2
2
|
import type { WaveformPoint } from '../../types';
|
|
3
3
|
import { type WaveformPointSource } from '../../core/waveformPointSource';
|
|
4
|
+
import { type IntegerZoomOptions } from './integerZoom';
|
|
4
5
|
interface PointSeriesSource {
|
|
5
6
|
points: WaveformPoint[];
|
|
6
7
|
source?: WaveformPointSource;
|
|
7
8
|
}
|
|
8
9
|
export type ZoomSeriesGroup = readonly PointSeriesSource[];
|
|
9
|
-
interface ZoomConstraintOptions {
|
|
10
|
+
interface ZoomConstraintOptions extends IntegerZoomOptions {
|
|
10
11
|
minZoomSpan?: number;
|
|
11
12
|
minVisiblePoints?: number;
|
|
12
13
|
maxZoomScale?: number | null;
|
|
@@ -8,6 +8,7 @@ interface Props {
|
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
10
|
interactive?: boolean;
|
|
11
|
+
showUnits?: boolean;
|
|
11
12
|
hiddenSeriesIds?: string[];
|
|
12
13
|
}
|
|
13
14
|
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
@@ -17,6 +18,7 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {},
|
|
|
17
18
|
}>, {
|
|
18
19
|
interactive: boolean;
|
|
19
20
|
hiddenSeriesIds: string[];
|
|
21
|
+
showUnits: boolean;
|
|
20
22
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
23
|
declare const _default: typeof __VLS_export;
|
|
22
24
|
export default _default;
|
|
@@ -14,10 +14,11 @@ interface Props {
|
|
|
14
14
|
axes?: WaveformAxesOptions;
|
|
15
15
|
timeUnit: 's' | 'ms';
|
|
16
16
|
yLabel?: string;
|
|
17
|
+
showAxisUnits?: boolean;
|
|
18
|
+
containYAxisEndpoints?: boolean;
|
|
19
|
+
containFrameStroke?: boolean;
|
|
17
20
|
cleanView?: boolean;
|
|
18
|
-
zeroLine?: Required<
|
|
19
|
-
visible: boolean;
|
|
20
|
-
};
|
|
21
|
+
zeroLine?: Required<WaveformZeroLineOptions>;
|
|
21
22
|
}
|
|
22
23
|
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
24
|
contextmenu: (mouseEvent: MouseEvent) => any;
|
|
@@ -38,10 +39,9 @@ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {},
|
|
|
38
39
|
}>, {
|
|
39
40
|
interactive: boolean;
|
|
40
41
|
cleanView: boolean;
|
|
41
|
-
zeroLine: Required<
|
|
42
|
-
visible: boolean;
|
|
43
|
-
};
|
|
42
|
+
zeroLine: Required<WaveformZeroLineOptions>;
|
|
44
43
|
interactionMode: WaveformInteractionMode;
|
|
44
|
+
showAxisUnits: boolean;
|
|
45
45
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
46
46
|
declare const _default: typeof __VLS_export;
|
|
47
47
|
export default _default;
|
|
@@ -7,7 +7,11 @@ interface Props {
|
|
|
7
7
|
axes?: WaveformAxesOptions;
|
|
8
8
|
timeUnit: 's' | 'ms';
|
|
9
9
|
yLabel?: string;
|
|
10
|
+
showUnits?: boolean;
|
|
11
|
+
containYAxisEndpoints?: boolean;
|
|
10
12
|
}
|
|
11
|
-
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
14
|
+
showUnits: boolean;
|
|
15
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
16
|
declare const _default: typeof __VLS_export;
|
|
13
17
|
export default _default;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { WaveformZeroLineOptions } from '../../types';
|
|
2
1
|
import type { TrackLayout } from '../core/types';
|
|
3
2
|
interface Props {
|
|
4
3
|
track: TrackLayout;
|
|
@@ -9,9 +8,6 @@ interface Props {
|
|
|
9
8
|
frameStyle: {
|
|
10
9
|
backgroundColor: string;
|
|
11
10
|
};
|
|
12
|
-
zeroLine: Required<Pick<WaveformZeroLineOptions, 'color' | 'width' | 'dash'>> & {
|
|
13
|
-
visible: boolean;
|
|
14
|
-
};
|
|
15
11
|
}
|
|
16
12
|
declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
13
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WaveformZeroLineOptions } from '../../types';
|
|
2
|
+
import type { TrackLayout } from '../core/types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
track: TrackLayout;
|
|
5
|
+
clipPathId: string;
|
|
6
|
+
innerWidth: number;
|
|
7
|
+
cleanView: boolean;
|
|
8
|
+
zeroLine: Required<WaveformZeroLineOptions>;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const recordedDampedPoints: number[][];
|
|
@@ -9,6 +9,7 @@ export interface DemoControlPanelModel {
|
|
|
9
9
|
displayMode: WaveformDisplayMode;
|
|
10
10
|
overlayMode: WaveformOverlayMode;
|
|
11
11
|
showTooltip: boolean;
|
|
12
|
+
integerZoom: boolean;
|
|
12
13
|
plotMarginTop: number;
|
|
13
14
|
plotMarginBottom: number;
|
|
14
15
|
cleanView: boolean;
|
|
@@ -20,6 +21,7 @@ export interface DemoControlPanelModel {
|
|
|
20
21
|
zeroLineVisible: boolean;
|
|
21
22
|
zeroLineColor: string;
|
|
22
23
|
zeroLineWidth: number;
|
|
24
|
+
zeroLineOpacity: number;
|
|
23
25
|
zeroLineDash: string;
|
|
24
26
|
zeroLineDashOptions: Array<SelectOption<string>>;
|
|
25
27
|
rowCount: number;
|
|
@@ -82,6 +84,7 @@ export interface DemoChartModel {
|
|
|
82
84
|
cleanView: boolean;
|
|
83
85
|
presentationMode: boolean;
|
|
84
86
|
showTooltip: boolean;
|
|
87
|
+
integerZoom: boolean;
|
|
85
88
|
plotMargin: WaveformPlotMargin;
|
|
86
89
|
zeroLine: WaveformZeroLineOptions;
|
|
87
90
|
frameWatermarkVisible: boolean;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
5
|
export { default as WaveformChart } from './components/WaveformChart.vue';
|
|
6
|
-
export type {
|
|
6
|
+
export type { WaveformChartProps } from './components/core/waveformChartTypes';
|
|
7
|
+
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, SingleWaveformData, WaveformLineType, WaveformLineStyle, WaveformPointType, WaveformErrorBarOptions, ResolvedWaveformErrorBarOptions, WaveformTypedValues, TypedSampleData, TypedPointData, WaveformSeries, WaveformData, NormalizedWaveformSeries, } from './types';
|
|
7
8
|
export type { WaveformGridOptions, WaveformGridLineOptions, WaveformGridTrackLines, } from './components/core/grid';
|
|
8
9
|
export { normalizeWaveformData, normalizeWaveformSeries } from './core';
|
|
9
10
|
export { paddedDomain, buildMinorTicks, displayTime, formatEndpointTime, formatAxisTime, formatTooltipTime, resolveTrackGeometry, clamp, type TimeUnit, type TrackGeometry, } from './utils';
|
|
@@ -11,6 +11,10 @@ export interface WaveformPoint {
|
|
|
11
11
|
/** Error above Y; overrides `error` for the upper side. */
|
|
12
12
|
upperError?: number;
|
|
13
13
|
}
|
|
14
|
+
/** Optional compact title and time-label placement at the card edges. */
|
|
15
|
+
export type WaveformLayoutPreset = 'default' | 'edge-compact';
|
|
16
|
+
/** Controls unit placement without changing series metadata. */
|
|
17
|
+
export type WaveformUnitDisplayMode = 'axis' | 'legend-single-series';
|
|
14
18
|
/**
|
|
15
19
|
* 显示模式
|
|
16
20
|
* - independent: 每个波形独立 Y 轴和缩放
|
|
@@ -44,6 +48,13 @@ export interface WaveformZoomEndPayload {
|
|
|
44
48
|
seriesIds?: string[];
|
|
45
49
|
gesture?: 'wheel' | 'box';
|
|
46
50
|
}
|
|
51
|
+
/** Final horizontal viewport after a pan; endpoints are always seconds. */
|
|
52
|
+
export interface WaveformPanEndPayload {
|
|
53
|
+
start: number;
|
|
54
|
+
end: number;
|
|
55
|
+
trackIndex?: number;
|
|
56
|
+
seriesIds?: string[];
|
|
57
|
+
}
|
|
47
58
|
/** Describes the X-axis viewport targeted by a user zoom gesture before rendering settles. */
|
|
48
59
|
export interface WaveformZoomIntentPayload {
|
|
49
60
|
start: number;
|
|
@@ -221,6 +232,8 @@ export interface WaveformAxesOptions {
|
|
|
221
232
|
splitNumber?: number;
|
|
222
233
|
/** Expands Y-axis domains to equal, human-friendly intervals. Defaults to true. */
|
|
223
234
|
nice?: boolean;
|
|
235
|
+
/** Adds this fraction of the automatic Y span above its maximum. Defaults to 0. */
|
|
236
|
+
upperPaddingRatio?: number;
|
|
224
237
|
};
|
|
225
238
|
}
|
|
226
239
|
/** Styling and visibility options for the horizontal zero-value reference line. */
|
|
@@ -233,4 +246,8 @@ export interface WaveformZeroLineOptions {
|
|
|
233
246
|
width?: number;
|
|
234
247
|
/** SVG stroke-dasharray. Defaults to '6 4'; use '' for a solid line. */
|
|
235
248
|
dash?: string;
|
|
249
|
+
/** Stroke opacity from 0 to 1. Defaults to 0.5; multiplies the color's alpha. */
|
|
250
|
+
opacity?: number;
|
|
251
|
+
/** Hide within this fraction of a Y-axis tick interval from either boundary. Defaults to 0.02. */
|
|
252
|
+
boundaryThreshold?: number;
|
|
236
253
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 类型定义统一导出
|
|
3
3
|
*/
|
|
4
|
-
export type { WaveformPoint, WaveformDisplayMode, WaveformOverlayMode, WaveformInteractionMode, WaveformXDomainStrategy, WaveformZoomIntentPayload, WaveformZoomEndPayload, 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, WaveformZeroLineOptions, } from './chart';
|
|
5
5
|
export type { SingleWaveformData, WaveformLineType, WaveformLineStyle, WaveformPointType, WaveformErrorBarOptions, ResolvedWaveformErrorBarOptions, WaveformTypedValues, TypedSampleData, TypedPointData, WaveformSeries, WaveformData, NormalizedWaveformSeries, } from './data';
|
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -48,11 +48,13 @@ const annotationsVisible = ref(true)
|
|
|
48
48
|
const cleanView = ref(false)
|
|
49
49
|
const presentationMode = ref(false)
|
|
50
50
|
const showTooltip = ref(true)
|
|
51
|
+
const integerZoom = ref(true)
|
|
51
52
|
const plotMarginTop = ref(18)
|
|
52
53
|
const plotMarginBottom = ref(52)
|
|
53
54
|
const zeroLineVisible = ref(true)
|
|
54
55
|
const zeroLineColor = ref('#ff0000')
|
|
55
56
|
const zeroLineWidth = ref(1)
|
|
57
|
+
const zeroLineOpacity = ref(0.5)
|
|
56
58
|
const zeroLineDash = ref('6 4')
|
|
57
59
|
const interactionMode = ref<WaveformInteractionMode>('zoom')
|
|
58
60
|
const legendPosition = ref<WaveformLegendPosition>('top-right')
|
|
@@ -127,6 +129,7 @@ const zeroLine = computed<WaveformZeroLineOptions>(() => ({
|
|
|
127
129
|
visible: zeroLineVisible.value,
|
|
128
130
|
color: zeroLineColor.value,
|
|
129
131
|
width: zeroLineWidth.value,
|
|
132
|
+
opacity: zeroLineOpacity.value,
|
|
130
133
|
dash: zeroLineDash.value,
|
|
131
134
|
}))
|
|
132
135
|
const plotMargin = computed<WaveformPlotMargin>(() => ({
|
|
@@ -298,6 +301,7 @@ const controlPanelModel = reactive({
|
|
|
298
301
|
displayMode,
|
|
299
302
|
overlayMode,
|
|
300
303
|
showTooltip,
|
|
304
|
+
integerZoom,
|
|
301
305
|
plotMarginTop,
|
|
302
306
|
plotMarginBottom,
|
|
303
307
|
cleanView,
|
|
@@ -309,6 +313,7 @@ const controlPanelModel = reactive({
|
|
|
309
313
|
zeroLineVisible,
|
|
310
314
|
zeroLineColor,
|
|
311
315
|
zeroLineWidth,
|
|
316
|
+
zeroLineOpacity,
|
|
312
317
|
zeroLineDash,
|
|
313
318
|
zeroLineDashOptions,
|
|
314
319
|
rowCount,
|
|
@@ -365,6 +370,7 @@ const chartModel = reactive({
|
|
|
365
370
|
cleanView,
|
|
366
371
|
presentationMode,
|
|
367
372
|
showTooltip,
|
|
373
|
+
integerZoom,
|
|
368
374
|
plotMargin,
|
|
369
375
|
zeroLine,
|
|
370
376
|
frameWatermarkVisible,
|
|
@@ -10,10 +10,13 @@ import WaveformChartView from './WaveformChartView.vue'
|
|
|
10
10
|
const props = withDefaults(defineProps<WaveformChartProps>(), {
|
|
11
11
|
displayMode: 'independent',
|
|
12
12
|
overlayMode: 'single-axis',
|
|
13
|
+
unitDisplayMode: 'axis',
|
|
14
|
+
layoutPreset: 'default',
|
|
13
15
|
yLabel: '幅值',
|
|
14
16
|
lineColor: '#0960bd',
|
|
15
17
|
showTooltip: true,
|
|
16
18
|
zoomable: true,
|
|
19
|
+
integerZoom: false,
|
|
17
20
|
pannable: false,
|
|
18
21
|
minVisiblePoints: 0,
|
|
19
22
|
xDomainStrategy: () => ({ type: 'integer-ms' }),
|
|
@@ -13,10 +13,14 @@ const {
|
|
|
13
13
|
displayMode,
|
|
14
14
|
activeInteractionMode,
|
|
15
15
|
isCleanView,
|
|
16
|
+
isEdgeCompact,
|
|
17
|
+
paginationVisible,
|
|
16
18
|
isPresentationMode,
|
|
17
19
|
selection,
|
|
18
20
|
containerStyle,
|
|
19
21
|
overlayMode,
|
|
22
|
+
unitDisplayMode,
|
|
23
|
+
showLegendUnits,
|
|
20
24
|
resolvedChartLeftMargin,
|
|
21
25
|
titleAreaHeight,
|
|
22
26
|
resolvedPlotMargin,
|
|
@@ -77,7 +81,6 @@ const {
|
|
|
77
81
|
xAxisTitleY,
|
|
78
82
|
hasChartArea,
|
|
79
83
|
gridOptions,
|
|
80
|
-
pageCount,
|
|
81
84
|
currentPage,
|
|
82
85
|
getPageSize,
|
|
83
86
|
pageableTracks,
|
|
@@ -116,6 +119,7 @@ function handleChartPointerLeave() {
|
|
|
116
119
|
`waveform-chart--interaction-${activeInteractionMode}`,
|
|
117
120
|
{
|
|
118
121
|
'waveform-chart--clean': isCleanView,
|
|
122
|
+
'waveform-chart--edge-compact': isEdgeCompact,
|
|
119
123
|
'waveform-chart--presentation': isPresentationMode,
|
|
120
124
|
'waveform-chart--panning': selection?.kind === 'pan',
|
|
121
125
|
},
|
|
@@ -233,6 +237,9 @@ function handleChartPointerLeave() {
|
|
|
233
237
|
:frame-number="resolveFrameNumber(track.id)"
|
|
234
238
|
:frame-style="frameStyle"
|
|
235
239
|
:axes="axes"
|
|
240
|
+
:show-axis-units="unitDisplayMode === 'axis'"
|
|
241
|
+
:contain-y-axis-endpoints="isEdgeCompact"
|
|
242
|
+
:contain-frame-stroke="isEdgeCompact"
|
|
236
243
|
:clean-view="isCleanView"
|
|
237
244
|
:zero-line="resolvedZeroLine"
|
|
238
245
|
:time-unit="timeUnit"
|
|
@@ -284,8 +291,12 @@ function handleChartPointerLeave() {
|
|
|
284
291
|
:transform="`translate(${track.left}, ${track.top})`"
|
|
285
292
|
>
|
|
286
293
|
<WaveformLegend
|
|
287
|
-
v-if="
|
|
294
|
+
v-if="
|
|
295
|
+
!track.isEmpty &&
|
|
296
|
+
(track.legendSeries.length > 1 || unitDisplayMode === 'legend-single-series')
|
|
297
|
+
"
|
|
288
298
|
:series="track.legendSeries"
|
|
299
|
+
:show-units="showLegendUnits"
|
|
289
300
|
:position="resolveLegendPosition(track.id)"
|
|
290
301
|
:orientation="resolveLegendOrientation(resolveLegendPosition(track.id))"
|
|
291
302
|
:background-color="legendBackgroundColor"
|
|
@@ -321,7 +332,7 @@ function handleChartPointerLeave() {
|
|
|
321
332
|
</svg>
|
|
322
333
|
|
|
323
334
|
<Pagination
|
|
324
|
-
v-if="
|
|
335
|
+
v-if="paginationVisible"
|
|
325
336
|
class="waveform-chart__pagination"
|
|
326
337
|
aria-label="波形分页"
|
|
327
338
|
:current="currentPage"
|
|
@@ -134,6 +134,7 @@ export function resolveGridCellGeometry(
|
|
|
134
134
|
slotHasSeries: boolean[] = [],
|
|
135
135
|
horizontalGap?: number,
|
|
136
136
|
showXAxis = true,
|
|
137
|
+
bottomAxisBandInMargin = false,
|
|
137
138
|
): GridCellGeometry[] {
|
|
138
139
|
const pageSize = getPageSize(options)
|
|
139
140
|
const seriesCount = slotHasSeries.filter(Boolean).length
|
|
@@ -164,7 +165,9 @@ export function resolveGridCellGeometry(
|
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
const totalVerticalGap = Math.max(0, rowCount - 1) * defaultGap
|
|
167
|
-
|
|
168
|
+
// The final row's ticks may use the chart bottom margin; intermediate bands stay in-grid.
|
|
169
|
+
const bottomBandCredit = bottomAxisBandInMargin && axisRows.has(rowCount - 1) ? X_AXIS_BAND : 0
|
|
170
|
+
const totalAxisBand = axisRows.size * X_AXIS_BAND - bottomBandCredit
|
|
168
171
|
const plotHeight = Math.max(1, (innerHeight - totalVerticalGap - totalAxisBand) / rowCount)
|
|
169
172
|
|
|
170
173
|
return Array.from({ length: filledLastRow ? seriesCount : pageSize }, (_, slotIndex) => {
|
|
@@ -161,10 +161,21 @@ export function resolveRenderedYAxisSeriesGroups(
|
|
|
161
161
|
yDomain?: WaveformYDomain,
|
|
162
162
|
yDomains?: Record<string, WaveformYDomain>,
|
|
163
163
|
viewportYDomains?: Record<string, [number, number]>,
|
|
164
|
+
upperPaddingRatio = 0,
|
|
164
165
|
): YAxisSeriesGroup[] {
|
|
165
166
|
const viewportYDomain = viewportYDomains?.[track.id]
|
|
166
167
|
return resolveYAxisSeriesGroups(track, overlayMode, yDomain, yDomains).map((group) =>
|
|
167
|
-
!group.fixed && viewportYDomain
|
|
168
|
+
!group.fixed && viewportYDomain
|
|
169
|
+
? { ...group, domain: viewportYDomain }
|
|
170
|
+
: !group.fixed && Number.isFinite(upperPaddingRatio) && upperPaddingRatio > 0
|
|
171
|
+
? {
|
|
172
|
+
...group,
|
|
173
|
+
domain: [
|
|
174
|
+
group.domain[0],
|
|
175
|
+
group.domain[1] + (group.domain[1] - group.domain[0]) * upperPaddingRatio,
|
|
176
|
+
] as WaveformYDomain,
|
|
177
|
+
}
|
|
178
|
+
: group,
|
|
168
179
|
)
|
|
169
180
|
}
|
|
170
181
|
|
|
@@ -255,6 +266,8 @@ export function buildYAxisSlots(
|
|
|
255
266
|
nice = true,
|
|
256
267
|
includeWithoutLastTick = false,
|
|
257
268
|
viewportYDomains?: Record<string, [number, number]>,
|
|
269
|
+
upperPaddingRatio = 0,
|
|
270
|
+
showUnits = true,
|
|
258
271
|
): { slots: YAxisSlot[]; clearance: { left: number; right: number } } {
|
|
259
272
|
const widths = new Map<string, number>()
|
|
260
273
|
tracks.forEach((track) => {
|
|
@@ -265,6 +278,7 @@ export function buildYAxisSlots(
|
|
|
265
278
|
yDomain,
|
|
266
279
|
yDomains,
|
|
267
280
|
viewportYDomains,
|
|
281
|
+
upperPaddingRatio,
|
|
268
282
|
).forEach((group) => {
|
|
269
283
|
const sideIndex = sideIndexes[group.side]++
|
|
270
284
|
const key = `${group.side}:${sideIndex}`
|
|
@@ -272,7 +286,7 @@ export function buildYAxisSlots(
|
|
|
272
286
|
group.domain,
|
|
273
287
|
nice,
|
|
274
288
|
undefined,
|
|
275
|
-
group.seriesList[0]?.unit,
|
|
289
|
+
showUnits ? group.seriesList[0]?.unit : undefined,
|
|
276
290
|
tickCount,
|
|
277
291
|
includeWithoutLastTick,
|
|
278
292
|
).tickTextWidth
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Conservative Ant pagination sizing, including first/last pages and both ellipses. */
|
|
2
|
+
export function resolveCompactPaginationBand(
|
|
3
|
+
visible: boolean,
|
|
4
|
+
width: number,
|
|
5
|
+
pageCount: number,
|
|
6
|
+
timeLabelCenter: number,
|
|
7
|
+
timeLabel: string,
|
|
8
|
+
): 0 | 16 | 40 {
|
|
9
|
+
if (!visible) return 0
|
|
10
|
+
if (width <= 520) return 40
|
|
11
|
+
const controls = Math.min(pageCount, 9) + 2
|
|
12
|
+
const paginationWidth = controls * 32 + controls * 8
|
|
13
|
+
// A full 18px em per character also accommodates wide glyphs and Chinese labels.
|
|
14
|
+
const labelRight = timeLabelCenter + (Array.from(timeLabel).length * 18) / 2
|
|
15
|
+
const availableWidth = width - 10 - labelRight - 8
|
|
16
|
+
return availableWidth >= paginationWidth ? 16 : 40
|
|
17
|
+
}
|
|
@@ -20,6 +20,7 @@ export interface RotatedTitleLayoutOptions {
|
|
|
20
20
|
naturalHeight: number
|
|
21
21
|
availableWidth: number
|
|
22
22
|
rotation: number
|
|
23
|
+
edgeCompact?: boolean
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
function clampPositive(value: number): number {
|
|
@@ -31,7 +32,10 @@ export function calculateRotatedTitleLayout({
|
|
|
31
32
|
naturalHeight,
|
|
32
33
|
availableWidth,
|
|
33
34
|
rotation,
|
|
35
|
+
edgeCompact = false,
|
|
34
36
|
}: RotatedTitleLayoutOptions): RotatedTitleLayout {
|
|
37
|
+
const verticalPadding = edgeCompact ? 8 : TITLE_AREA_VERTICAL_PADDING
|
|
38
|
+
const minimumHeight = edgeCompact ? 0 : TITLE_AREA_MIN_HEIGHT
|
|
35
39
|
const safeNaturalWidth = clampPositive(naturalWidth)
|
|
36
40
|
const safeNaturalHeight = clampPositive(naturalHeight)
|
|
37
41
|
const safeAvailableWidth = clampPositive(availableWidth)
|
|
@@ -53,13 +57,13 @@ export function calculateRotatedTitleLayout({
|
|
|
53
57
|
textHeight,
|
|
54
58
|
visualWidth: textWidth,
|
|
55
59
|
visualHeight: textHeight,
|
|
56
|
-
areaHeight: Math.max(
|
|
60
|
+
areaHeight: Math.max(minimumHeight, textHeight + verticalPadding),
|
|
57
61
|
scale: 1,
|
|
58
62
|
wrapped: lineCount > 1,
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
const maximumVisualHeight = TITLE_AREA_MAX_HEIGHT -
|
|
66
|
+
const maximumVisualHeight = TITLE_AREA_MAX_HEIGHT - verticalPadding
|
|
63
67
|
const naturalVisualWidth = safeNaturalWidth * absoluteCosine + safeNaturalHeight * absoluteSine
|
|
64
68
|
const naturalVisualHeight = safeNaturalWidth * absoluteSine + safeNaturalHeight * absoluteCosine
|
|
65
69
|
const scale = Math.min(
|
|
@@ -71,7 +75,7 @@ export function calculateRotatedTitleLayout({
|
|
|
71
75
|
const visualHeight = naturalVisualHeight * scale
|
|
72
76
|
const areaHeight = Math.min(
|
|
73
77
|
TITLE_AREA_MAX_HEIGHT,
|
|
74
|
-
Math.max(
|
|
78
|
+
Math.max(minimumHeight, visualHeight + verticalPadding),
|
|
75
79
|
)
|
|
76
80
|
|
|
77
81
|
return {
|