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.
Files changed (81) hide show
  1. package/README.md +146 -5
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1326 -1118
  4. package/dist/style.css +1 -1
  5. package/dist/types/components/WaveformChart.vue.d.ts +7 -2
  6. package/dist/types/components/core/constants.d.ts +2 -0
  7. package/dist/types/components/core/grid.d.ts +1 -1
  8. package/dist/types/components/core/layout.d.ts +2 -2
  9. package/dist/types/components/core/pagination.d.ts +2 -0
  10. package/dist/types/components/core/title.d.ts +2 -1
  11. package/dist/types/components/core/trackLayoutBuilder.d.ts +5 -0
  12. package/dist/types/components/core/types.d.ts +2 -1
  13. package/dist/types/components/core/useWaveformChartController.d.ts +9 -0
  14. package/dist/types/components/core/useWaveformLayout.d.ts +1 -0
  15. package/dist/types/components/core/useWaveformPresentation.d.ts +3 -0
  16. package/dist/types/components/core/useWaveformYAxisLayout.d.ts +31 -0
  17. package/dist/types/components/core/waveformChartTypes.d.ts +11 -2
  18. package/dist/types/components/core/yAxisLayoutMetrics.d.ts +1 -1
  19. package/dist/types/components/core/yAxisTitleLayout.d.ts +4 -0
  20. package/dist/types/components/data/types.d.ts +1 -1
  21. package/dist/types/components/interaction/integerZoom.d.ts +12 -0
  22. package/dist/types/components/interaction/interactionTarget.d.ts +1 -0
  23. package/dist/types/components/interaction/remoteViewport.d.ts +8 -0
  24. package/dist/types/components/interaction/useWaveformViewport.d.ts +1 -2
  25. package/dist/types/components/interaction/viewportDomain.d.ts +1 -1
  26. package/dist/types/components/interaction/viewportPan.d.ts +4 -0
  27. package/dist/types/components/interaction/zoomConstraints.d.ts +2 -1
  28. package/dist/types/components/rendering/WaveformLegend.vue.d.ts +2 -0
  29. package/dist/types/components/rendering/WaveformTrack.vue.d.ts +6 -6
  30. package/dist/types/components/rendering/WaveformTrackAxes.vue.d.ts +5 -1
  31. package/dist/types/components/rendering/WaveformTrackBackdrop.vue.d.ts +0 -4
  32. package/dist/types/components/rendering/WaveformZeroLines.vue.d.ts +12 -0
  33. package/dist/types/data/recordedDampedWaveform.d.ts +1 -0
  34. package/dist/types/demo/types.d.ts +3 -0
  35. package/dist/types/index.d.ts +2 -1
  36. package/dist/types/types/chart.d.ts +17 -0
  37. package/dist/types/types/index.d.ts +1 -1
  38. package/package.json +1 -1
  39. package/src/App.vue +6 -0
  40. package/src/components/WaveformChart.css +5 -0
  41. package/src/components/WaveformChart.vue +3 -0
  42. package/src/components/WaveformChartView.vue +14 -3
  43. package/src/components/core/constants.ts +2 -0
  44. package/src/components/core/grid.ts +4 -1
  45. package/src/components/core/layout.ts +16 -2
  46. package/src/components/core/pagination.ts +17 -0
  47. package/src/components/core/title.ts +7 -3
  48. package/src/components/core/trackLayoutBuilder.ts +39 -59
  49. package/src/components/core/types.ts +2 -0
  50. package/src/components/core/useWaveformChartController.ts +17 -1
  51. package/src/components/core/useWaveformChartLifecycle.ts +11 -17
  52. package/src/components/core/useWaveformLayout.ts +67 -107
  53. package/src/components/core/useWaveformPresentation.ts +27 -3
  54. package/src/components/core/useWaveformYAxisLayout.ts +140 -0
  55. package/src/components/core/waveformChartTypes.ts +15 -0
  56. package/src/components/core/yAxisLayoutMetrics.ts +11 -2
  57. package/src/components/core/yAxisTitleLayout.ts +78 -0
  58. package/src/components/data/types.ts +3 -0
  59. package/src/components/interaction/integerZoom.ts +64 -0
  60. package/src/components/interaction/interactionTarget.ts +10 -0
  61. package/src/components/interaction/remoteViewport.ts +53 -0
  62. package/src/components/interaction/useWaveformViewport.ts +16 -58
  63. package/src/components/interaction/useWaveformZoom.ts +13 -11
  64. package/src/components/interaction/viewportDomain.ts +11 -3
  65. package/src/components/interaction/viewportPan.ts +82 -0
  66. package/src/components/interaction/zoomConstraints.ts +7 -5
  67. package/src/components/rendering/WaveformLegend.vue +10 -1
  68. package/src/components/rendering/WaveformTrack.vue +24 -6
  69. package/src/components/rendering/WaveformTrackAxes.vue +16 -5
  70. package/src/components/rendering/WaveformTrackBackdrop.vue +2 -34
  71. package/src/components/rendering/WaveformZeroLines.vue +53 -0
  72. package/src/data/recordedDampedWaveform.ts +3 -0
  73. package/src/data/simulatedWaveforms.ts +12 -10
  74. package/src/demo/DemoChartHost.vue +1 -0
  75. package/src/demo/DemoGridFrameControls.vue +12 -0
  76. package/src/demo/DemoViewControls.vue +4 -0
  77. package/src/demo/types.ts +3 -0
  78. package/src/index.ts +4 -0
  79. package/src/styles.css +3 -3
  80. package/src/types/chart.ts +20 -0
  81. package/src/types/index.ts +3 -0
@@ -0,0 +1,82 @@
1
+ import type { TrackLayout } from '../core/types'
2
+ import { hasFixedYDomainForTrack } from '../core/yDomain'
3
+ import type { ViewportSelectionState } from '../core/waveformChartTypes'
4
+ import type { ViewportContext } from './useWaveformViewport'
5
+ import { clampViewportDomain as clampDomain } from './viewportDomain'
6
+ import { alignIntegerPanDomain } from './integerZoom'
7
+ import { remotePanBoundary } from './remoteViewport'
8
+ import { transformForDomain } from './zoomConstraints'
9
+
10
+ export function createViewportPan(context: ViewportContext) {
11
+ const {
12
+ props,
13
+ emit,
14
+ resolveInitialTrackDomain,
15
+ initialXDomain,
16
+ independentTransforms,
17
+ sharedTransform,
18
+ innerWidth,
19
+ trackLayouts,
20
+ chartTracks,
21
+ independentYDomains,
22
+ sharedYDomains,
23
+ } = context
24
+ const applyPan = (active: ViewportSelectionState, track: TrackLayout) => {
25
+ const width = track.width || 1
26
+ const height = track.height || 1
27
+ const dx = active.currentX - active.startX
28
+ const dy = active.currentY - active.startY
29
+ const xSpan = active.xDomain[1] - active.xDomain[0]
30
+ const sourceXDomain = active.independent
31
+ ? resolveInitialTrackDomain(track)
32
+ : initialXDomain.value
33
+ const boundary = remotePanBoundary(props) ?? sourceXDomain
34
+ const nextX = clampDomain(
35
+ alignIntegerPanDomain(
36
+ clampDomain(
37
+ [active.xDomain[0] - (dx / width) * xSpan, active.xDomain[1] - (dx / width) * xSpan],
38
+ boundary,
39
+ ),
40
+ props,
41
+ ),
42
+ boundary,
43
+ )
44
+ if (active.independent) {
45
+ const nextTransforms = [...independentTransforms.value]
46
+ nextTransforms[track.index] = transformForDomain(nextX, sourceXDomain, width)
47
+ independentTransforms.value = nextTransforms
48
+ } else {
49
+ sharedTransform.value = transformForDomain(nextX, sourceXDomain, innerWidth.value)
50
+ }
51
+ if (remotePanBoundary(props)) {
52
+ emit('zoom-change', nextX)
53
+ return nextX
54
+ }
55
+ const targets = active.independent
56
+ ? [track]
57
+ : trackLayouts.value.filter((target) => target.hasVisibleSeries)
58
+ const nextIndependentDomains = { ...independentYDomains.value }
59
+ const nextSharedDomains = { ...sharedYDomains.value }
60
+ targets.forEach((target) => {
61
+ const chartTrack = chartTracks.value.find((item) => item.id === target.id)
62
+ if (chartTrack && hasFixedYDomainForTrack(chartTrack, props.yDomain, props.yDomains)) {
63
+ return
64
+ }
65
+ const key = target.series?.trackId ?? target.series?.id ?? target.id
66
+ const source = active.yDomains[key] ?? (target.yScale.domain() as [number, number])
67
+ const boundary = chartTrack?.yDomain ?? source
68
+ const ySpan = source[1] - source[0]
69
+ const nextY = clampDomain(
70
+ [source[0] + (dy / height) * ySpan, source[1] + (dy / height) * ySpan],
71
+ boundary,
72
+ )
73
+ if (active.independent) nextIndependentDomains[target.index] = nextY
74
+ else nextSharedDomains[key] = nextY
75
+ })
76
+ if (active.independent) independentYDomains.value = nextIndependentDomains
77
+ else sharedYDomains.value = nextSharedDomains
78
+ emit('zoom-change', nextX)
79
+ return nextX
80
+ }
81
+ return applyPan
82
+ }
@@ -3,6 +3,7 @@ import { scaleLinear, zoomIdentity, type ZoomTransform } from 'd3'
3
3
  import type { WaveformPoint } from '../../types'
4
4
  import { pointSourceFromPoints, type WaveformPointSource } from '../../core/waveformPointSource'
5
5
  import { ZOOM_CONSTRAINTS } from '../core/constants'
6
+ import { alignIntegerZoomDomain, type IntegerZoomOptions } from './integerZoom'
6
7
 
7
8
  interface PointSeriesSource {
8
9
  points: WaveformPoint[]
@@ -11,7 +12,7 @@ interface PointSeriesSource {
11
12
 
12
13
  export type ZoomSeriesGroup = readonly PointSeriesSource[]
13
14
 
14
- interface ZoomConstraintOptions {
15
+ interface ZoomConstraintOptions extends IntegerZoomOptions {
15
16
  minZoomSpan?: number
16
17
  minVisiblePoints?: number
17
18
  maxZoomScale?: number | null
@@ -72,7 +73,7 @@ export function resolveMinimumZoomSpan(
72
73
  groups: readonly ZoomSeriesGroup[],
73
74
  options: ZoomConstraintOptions,
74
75
  ): number {
75
- const normalized = normalizedBoundary(boundary)
76
+ const normalized = alignIntegerZoomDomain(normalizedBoundary(boundary), options)
76
77
  const boundarySpan = normalized[1] - normalized[0]
77
78
  if (!Number.isFinite(boundarySpan) || boundarySpan <= 0) return 0
78
79
  const configuredSpan =
@@ -88,7 +89,8 @@ export function resolveMinimumZoomSpan(
88
89
  : options.maxZoomScale !== null && configuredSpan === 0 && required === 0
89
90
  ? boundarySpan / ZOOM_CONSTRAINTS.DEFAULT_MAX_SCALE
90
91
  : 0
91
- return Math.max(configuredSpan, pointSpan, scaleSpan)
92
+ const integerSpan = options.integerZoom ? (options.timeUnit === 's' ? 1 : 0.001) : 0
93
+ return Math.max(configuredSpan, pointSpan, scaleSpan, integerSpan)
92
94
  }
93
95
 
94
96
  function expandToMinimumPoints(
@@ -139,7 +141,7 @@ export function constrainZoomDomain(
139
141
  groups: readonly ZoomSeriesGroup[],
140
142
  options: ZoomConstraintOptions,
141
143
  ): [number, number] {
142
- const normalized = normalizedBoundary(boundary)
144
+ const normalized = alignIntegerZoomDomain(normalizedBoundary(boundary), options)
143
145
  const boundarySpan = normalized[1] - normalized[0]
144
146
  if (!Number.isFinite(boundarySpan) || boundarySpan <= 0) return normalized
145
147
  if (Math.abs(domain[1] - domain[0]) >= boundarySpan * (1 - 1e-12)) return normalized
@@ -157,7 +159,7 @@ export function constrainZoomDomain(
157
159
  const span = Math.max(minimumSpan, Math.min(boundarySpan, expanded[1] - expanded[0]))
158
160
  const center = (expanded[0] + expanded[1]) / 2
159
161
  const start = Math.max(normalized[0], Math.min(center - span / 2, normalized[1] - span))
160
- return [start, start + span]
162
+ return alignIntegerZoomDomain([start, start + span], options)
161
163
  }
162
164
 
163
165
  export function transformForDomain(
@@ -18,11 +18,13 @@ interface Props {
18
18
  width: number
19
19
  height: number
20
20
  interactive?: boolean
21
+ showUnits?: boolean
21
22
  hiddenSeriesIds?: string[]
22
23
  }
23
24
 
24
25
  const props = withDefaults(defineProps<Props>(), {
25
26
  interactive: false,
27
+ showUnits: false,
26
28
  hiddenSeriesIds: () => [],
27
29
  })
28
30
  const emit = defineEmits<{
@@ -30,6 +32,11 @@ const emit = defineEmits<{
30
32
  }>()
31
33
  const hiddenSeriesIdSet = computed(() => new Set(props.hiddenSeriesIds))
32
34
 
35
+ function legendLabel(series: DisplaySeries): string {
36
+ const unit = series.unit?.trim()
37
+ return props.showUnits && unit && unit !== '--' ? `${series.name} (${unit})` : series.name
38
+ }
39
+
33
40
  function isHidden(seriesId: string): boolean {
34
41
  return hiddenSeriesIdSet.value.has(seriesId)
35
42
  }
@@ -113,7 +120,9 @@ function toggleSeries(seriesId: string) {
113
120
  transform="translate(13 8)"
114
121
  />
115
122
  </svg>
116
- <span class="waveform-legend__label" :title="item.name">{{ item.name }}</span>
123
+ <span class="waveform-legend__label" :title="legendLabel(item)">{{
124
+ legendLabel(item)
125
+ }}</span>
117
126
  </button>
118
127
  </div>
119
128
  </div>
@@ -6,6 +6,7 @@ import type { WaveformAxesOptions, WaveformFrameStyle, WaveformZeroLineOptions }
6
6
  import type { TrackLayout } from '../core/types'
7
7
  import type { WaveformDisplayMode, WaveformInteractionMode } from '../data/types'
8
8
  import WaveformSeriesLayer from './WaveformSeriesLayer.vue'
9
+ import WaveformZeroLines from './WaveformZeroLines.vue'
9
10
  import WaveformTrackAxes from './WaveformTrackAxes.vue'
10
11
  import WaveformTrackBackdrop from './WaveformTrackBackdrop.vue'
11
12
 
@@ -22,10 +23,11 @@ interface Props {
22
23
  axes?: WaveformAxesOptions
23
24
  timeUnit: 's' | 'ms'
24
25
  yLabel?: string
26
+ showAxisUnits?: boolean
27
+ containYAxisEndpoints?: boolean
28
+ containFrameStroke?: boolean
25
29
  cleanView?: boolean
26
- zeroLine?: Required<Pick<WaveformZeroLineOptions, 'color' | 'width' | 'dash'>> & {
27
- visible: boolean
28
- }
30
+ zeroLine?: Required<WaveformZeroLineOptions>
29
31
  }
30
32
 
31
33
  interface Emits {
@@ -42,11 +44,14 @@ const props = withDefaults(defineProps<Props>(), {
42
44
  interactionMode: 'zoom',
43
45
  interactive: true,
44
46
  cleanView: false,
47
+ showAxisUnits: true,
45
48
  zeroLine: () => ({
46
49
  visible: true,
47
50
  color: ZERO_LINE_DEFAULTS.COLOR,
48
51
  width: ZERO_LINE_DEFAULTS.WIDTH,
49
52
  dash: ZERO_LINE_DEFAULTS.DASH,
53
+ opacity: ZERO_LINE_DEFAULTS.OPACITY,
54
+ boundaryThreshold: ZERO_LINE_DEFAULTS.BOUNDARY_THRESHOLD,
50
55
  }),
51
56
  })
52
57
  const emit = defineEmits<Emits>()
@@ -66,6 +71,9 @@ const resolvedFrameStyle = computed(() => {
66
71
  backgroundColor: props.frameStyle?.backgroundColor || 'transparent',
67
72
  }
68
73
  })
74
+ const frameInset = computed(() =>
75
+ props.containFrameStroke ? resolvedFrameStyle.value.borderWidth / 2 : 0,
76
+ )
69
77
  </script>
70
78
 
71
79
  <template>
@@ -89,7 +97,6 @@ const resolvedFrameStyle = computed(() => {
89
97
  :clean-view="cleanView"
90
98
  :frame-number="frameNumber"
91
99
  :frame-style="resolvedFrameStyle"
92
- :zero-line="zeroLine"
93
100
  />
94
101
  <WaveformTrackAxes
95
102
  :track="track"
@@ -98,13 +105,17 @@ const resolvedFrameStyle = computed(() => {
98
105
  :axes="axes"
99
106
  :time-unit="timeUnit"
100
107
  :y-label="yLabel"
108
+ :show-units="showAxisUnits"
109
+ :contain-y-axis-endpoints="containYAxisEndpoints"
101
110
  />
102
111
 
103
112
  <rect
104
113
  v-if="!track.isEmpty"
105
114
  class="waveform-track__plot-frame waveform-chart__plot-frame"
106
- :width="track.width ?? innerWidth"
107
- :height="track.height"
115
+ :x="containFrameStroke ? frameInset : undefined"
116
+ :y="containFrameStroke ? frameInset : undefined"
117
+ :width="Math.max(0, (track.width ?? innerWidth) - frameInset * 2)"
118
+ :height="Math.max(0, track.height - frameInset * 2)"
108
119
  fill="none"
109
120
  :stroke="resolvedFrameStyle.borderColor"
110
121
  :stroke-width="resolvedFrameStyle.borderWidth"
@@ -120,6 +131,13 @@ const resolvedFrameStyle = computed(() => {
120
131
  />
121
132
 
122
133
  <WaveformSeriesLayer :track="track" :clip-path-id="clipPathId" />
134
+ <WaveformZeroLines
135
+ :track="track"
136
+ :clip-path-id="clipPathId"
137
+ :inner-width="innerWidth"
138
+ :clean-view="cleanView"
139
+ :zero-line="zeroLine"
140
+ />
123
141
 
124
142
  <rect
125
143
  v-if="!track.isEmpty && track.hasVisibleSeries && displayMode === 'independent'"
@@ -15,9 +15,11 @@ interface Props {
15
15
  axes?: WaveformAxesOptions
16
16
  timeUnit: 's' | 'ms'
17
17
  yLabel?: string
18
+ showUnits?: boolean
19
+ containYAxisEndpoints?: boolean
18
20
  }
19
21
 
20
- const props = defineProps<Props>()
22
+ const props = withDefaults(defineProps<Props>(), { showUnits: true })
21
23
  const xAxisElement = ref<SVGGElement>()
22
24
  const yAxisElements = ref<SVGGElement[]>([])
23
25
 
@@ -44,7 +46,7 @@ function renderAxes() {
44
46
  props.track.yAxes.forEach((axis, index) => {
45
47
  const element = yAxisElements.value[index]
46
48
  if (!element) return
47
- const unit = axis.seriesList[0]?.unit
49
+ const unit = props.showUnits ? axis.seriesList[0]?.unit : undefined
48
50
  const yAxis = (axis.side === 'left' ? axisLeft(axis.scale) : axisRight(axis.scale))
49
51
  .tickFormat((value) =>
50
52
  formatYAxisTickLabel(
@@ -62,11 +64,18 @@ function renderAxes() {
62
64
  const selection = select(element)
63
65
  selection.call(yAxis)
64
66
  const lowestTick = Math.min(...axis.tickValues)
67
+ const highestTick = props.containYAxisEndpoints ? Math.max(...axis.tickValues) : undefined
65
68
  selection
66
69
  .selectAll<SVGTextElement, number>('.tick text')
67
70
  .attr('y', null)
68
- .attr('dy', (value) => (value === lowestTick ? '0' : '0.32em'))
69
- .attr('dominant-baseline', (value) => (value === lowestTick ? 'text-after-edge' : null))
71
+ .attr('dy', (value) => (value === lowestTick || value === highestTick ? '0' : '0.32em'))
72
+ .attr('dominant-baseline', (value) =>
73
+ value === lowestTick
74
+ ? 'text-after-edge'
75
+ : value === highestTick
76
+ ? 'text-before-edge'
77
+ : null,
78
+ )
70
79
  selection
71
80
  .selectAll('path.domain')
72
81
  .attr('display', props.axes?.y?.lineVisible === false ? 'none' : null)
@@ -83,7 +92,7 @@ function renderAxes() {
83
92
  props.track.xScale.domain() as [number, number],
84
93
  props.timeUnit,
85
94
  'tick',
86
- props.axes?.x?.labelFormatter,
95
+ props.axes?.x?.labelFormatter ?? props.track.xAxisLabelFormatter,
87
96
  ),
88
97
  )
89
98
  .tickSize(-4)
@@ -107,6 +116,8 @@ watch(
107
116
  () => props.track.xAxisTickValues,
108
117
  () => props.track.yAxisTickValues,
109
118
  () => props.timeUnit,
119
+ () => props.showUnits,
120
+ () => props.containYAxisEndpoints,
110
121
  () => props.axes?.x?.labelFormatter,
111
122
  () => props.axes?.x?.lineVisible,
112
123
  () => props.axes?.y?.lineVisible,
@@ -1,6 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { WaveformZeroLineOptions } from '../../types'
3
- import type { TrackLayout, WaveformYAxisLayout } from '../core/types'
2
+ import type { TrackLayout } from '../core/types'
4
3
 
5
4
  interface Props {
6
5
  track: TrackLayout
@@ -11,18 +10,9 @@ interface Props {
11
10
  frameStyle: {
12
11
  backgroundColor: string
13
12
  }
14
- zeroLine: Required<Pick<WaveformZeroLineOptions, 'color' | 'width' | 'dash'>> & {
15
- visible: boolean
16
- }
17
13
  }
18
14
 
19
- const props = defineProps<Props>()
20
-
21
- function zeroLineY(axis: WaveformYAxisLayout): number | null {
22
- const [minimum, maximum] = axis.scale.domain()
23
- if (!props.zeroLine.visible || minimum > 0 || maximum < 0) return null
24
- return axis.scale(0)
25
- }
15
+ defineProps<Props>()
26
16
  </script>
27
17
 
28
18
  <template>
@@ -98,28 +88,6 @@ function zeroLineY(axis: WaveformYAxisLayout): number | null {
98
88
  </g>
99
89
  </g>
100
90
 
101
- <g
102
- v-if="!track.isEmpty && track.hasVisibleSeries && zeroLine.visible && !cleanView"
103
- class="waveform-track__zero-lines waveform-chart__zero-lines"
104
- :clip-path="`url(#${clipPathId}-${track.index})`"
105
- aria-hidden="true"
106
- >
107
- <template v-for="axis in track.yAxes" :key="`zero-line-${track.index}-${axis.index}`">
108
- <line
109
- v-if="zeroLineY(axis) !== null"
110
- class="waveform-track__zero-line waveform-chart__zero-line"
111
- :data-y-axis-index="axis.index"
112
- x1="0"
113
- :x2="track.width ?? innerWidth"
114
- :y1="zeroLineY(axis) ?? 0"
115
- :y2="zeroLineY(axis) ?? 0"
116
- :stroke="zeroLine.color"
117
- :stroke-width="zeroLine.width"
118
- :stroke-dasharray="zeroLine.dash || undefined"
119
- />
120
- </template>
121
- </g>
122
-
123
91
  <text
124
92
  v-if="!track.isEmpty && track.hasVisibleSeries && frameNumber !== undefined && !cleanView"
125
93
  class="waveform-track__watermark waveform-chart__watermark"
@@ -0,0 +1,53 @@
1
+ <script setup lang="ts">
2
+ import type { WaveformZeroLineOptions } from '../../types'
3
+ import type { TrackLayout, WaveformYAxisLayout } from '../core/types'
4
+
5
+ const props = defineProps<{
6
+ track: TrackLayout
7
+ clipPathId: string
8
+ innerWidth: number
9
+ cleanView: boolean
10
+ zeroLine: Required<WaveformZeroLineOptions>
11
+ }>()
12
+
13
+ function zeroLineY(axis: WaveformYAxisLayout): number | null {
14
+ const [minimum, maximum] = axis.scale.domain()
15
+ const tickInterval = Math.abs(axis.tickValues[1] - axis.tickValues[0])
16
+ const margin = tickInterval * props.zeroLine.boundaryThreshold
17
+ if (
18
+ !props.zeroLine.visible ||
19
+ minimum >= 0 ||
20
+ maximum <= 0 ||
21
+ -minimum < margin ||
22
+ maximum < margin
23
+ )
24
+ return null
25
+ return axis.scale(0)
26
+ }
27
+ </script>
28
+
29
+ <template>
30
+ <g
31
+ v-if="!track.isEmpty && track.hasVisibleSeries && zeroLine.visible && !cleanView"
32
+ class="waveform-track__zero-lines waveform-chart__zero-lines"
33
+ :clip-path="`url(#${clipPathId}-${track.index})`"
34
+ aria-hidden="true"
35
+ pointer-events="none"
36
+ >
37
+ <template v-for="axis in track.yAxes" :key="`zero-line-${track.index}-${axis.index}`">
38
+ <line
39
+ v-if="zeroLineY(axis) !== null"
40
+ class="waveform-track__zero-line waveform-chart__zero-line"
41
+ :data-y-axis-index="axis.index"
42
+ x1="0"
43
+ :x2="track.width ?? innerWidth"
44
+ :y1="zeroLineY(axis) ?? 0"
45
+ :y2="zeroLineY(axis) ?? 0"
46
+ :stroke="zeroLine.color"
47
+ :stroke-opacity="zeroLine.opacity"
48
+ :stroke-width="zeroLine.width"
49
+ :stroke-dasharray="zeroLine.dash || undefined"
50
+ />
51
+ </template>
52
+ </g>
53
+ </template>
@@ -0,0 +1,3 @@
1
+ // Source: 13921.txt, X(ms), 2M:13921:V22ca_TFN(V). Preserve all 1,000 samples.
2
+ // prettier-ignore
3
+ export const recordedDampedPoints: number[][] = [[-4000,184.7562],[-3989.99,-189.8833],[-3979.98,181.4603],[-3969.97,-186.9535],[-3959.96,178.8968],[-3949.95,-188.6625],[-3939.941,188.5405],[-3929.931,-190.4936],[-3919.921,183.9017],[-3909.911,-181.4603],[-3899.901,183.0472],[-3889.891,-187.4418],[-3879.881,193.4234],[-3869.871,-192.813],[-3859.861,186.4652],[-3849.851,-194.0337],[-3839.841,186.099],[-3829.832,-184.6342],[-3819.822,181.4603],[-3809.812,-187.3198],[-3799.802,183.2914],[-3789.792,-185.977],[-3779.782,184.6342],[-3769.772,-188.2963],[-3759.762,190.4936],[-3749.752,-185.0004],[-3739.742,194.8882],[-3729.732,-186.8315],[-3719.723,178.6526],[-3709.713,-186.7094],[-3699.703,185.6107],[-3689.693,-190.8598],[-3679.683,188.1743],[-3669.673,-190.8598],[-3659.663,191.4702],[-3649.653,-191.104],[-3639.643,190.4936],[-3629.633,-187.0756],[-3619.623,185.8549],[-3609.614,-191.104],[-3599.604,191.9585],[-3589.594,-191.104],[-3579.584,192.3247],[-3569.574,-186.7094],[-3559.564,176.5774],[-3549.554,-190.3716],[-3539.544,185.3666],[-3529.534,-191.2261],[-3519.524,193.5454],[-3509.514,-192.2026],[-3499.505,192.4468],[-3489.495,-193.5454],[-3479.485,189.395],[-3469.475,-192.0806],[-3459.465,178.4085],[-3449.455,-187.808],[-3439.445,184.1459],[-3429.435,-198.3062],[-3419.425,180.972],[-3409.415,-191.2261],[-3399.405,192.2026],[-3389.396,-194.1558],[-3379.386,195.2544],[-3369.376,-188.6625],[-3359.366,183.1693],[-3349.356,-178.5306],[-3339.346,182.8031],[-3329.336,-204.1657],[-3319.326,188.9067],[-3309.316,-192.813],[-3299.306,193.0571],[-3289.296,-189.5171],[-3279.286,184.5121],[-3269.277,-185.1225],[-3259.267,177.4319],[-3249.257,-186.4652],[-3239.247,185.4887],[-3229.237,-195.8648],[-3219.227,187.3198],[-3209.217,-189.8833],[-3199.207,192.3247],[-3189.197,-188.0522],[-3179.187,189.1508],[-3169.177,-189.7612],[-3159.168,193.5454],[-3149.158,-191.7144],[-3139.148,187.4418],[-3129.138,-202.5788],[-3119.128,191.5923],[-3109.118,-189.395],[-3099.108,191.7144],[-3089.098,-200.7477],[-3079.088,194.0337],[-3069.078,-197.2076],[-3059.068,196.9635],[-3049.059,-198.6725],[-3039.049,202.2126],[-3029.039,-195.2544],[-3019.029,196.3531],[-3009.019,-189.0288],[-2999.009,195.8648],[-2988.999,-206.363],[-2978.989,197.5738],[-2968.979,-191.5923],[-2958.969,198.1842],[-2948.959,-198.1842],[-2938.95,204.0436],[-2928.94,-193.3013],[-2918.93,193.0571],[-2908.92,-195.3765],[-2898.91,195.4986],[-2888.9,-196.231],[-2878.89,191.5923],[-2868.88,-192.6909],[-2858.87,193.9117],[-2848.86,-200.1373],[-2838.85,196.231],[-2828.841,-184.1459],[-2818.831,190.3716],[-2808.821,-196.231],[-2798.811,196.5972],[-2788.801,-202.3346],[-2778.791,182.8031],[-2768.781,-192.813],[-2758.771,196.231],[-2748.761,-198.5504],[-2738.751,206.8513],[-2728.741,-197.6959],[-2718.732,191.104],[-2708.722,-194.7662],[-2698.712,192.9351],[-2688.702,-199.1608],[-2678.692,188.7846],[-2668.682,-197.6959],[-2658.672,204.7761],[-2648.662,-203.5554],[-2638.652,208.4382],[-2628.642,-193.0571],[-2618.632,189.6391],[-2608.623,-196.7193],[-2598.613,201.8463],[-2588.603,-203.4333],[-2578.593,195.3765],[-2568.583,-195.7427],[-2558.573,193.6675],[-2548.563,-205.0202],[-2538.553,197.2076],[-2528.543,-199.2828],[-2518.533,186.2211],[-2508.523,-198.1842],[-2498.514,202.945],[-2488.504,-200.9918],[-2478.494,193.3013],[-2468.484,-197.2076],[-2458.474,197.818],[-2448.464,-205.1423],[-2438.454,195.0103],[-2428.444,-203.7995],[-2418.434,194.2779],[-2408.424,-196.8414],[-2398.414,205.0202],[-2388.405,-192.9351],[-2378.395,190.9819],[-2368.385,-198.3062],[-2358.375,209.781],[-2348.365,-205.1423],[-2338.355,201.7243],[-2328.345,-194.6441],[-2318.335,193.5454],[-2308.325,-196.7193],[-2298.315,193.7896],[-2288.305,-193.0571],[-2278.296,196.7193],[-2268.286,-199.1608],[-2258.276,201.3581],[-2248.266,-209.4148],[-2238.256,203.7995],[-2228.246,-199.527],[-2218.236,195.4986],[-2208.226,-194.6441],[-2198.216,199.8932],[-2188.206,-194.0337],[-2178.196,208.3162],[-2168.187,-201.6022],[-2158.177,209.4148],[-2148.167,-209.4148],[-2138.157,198.4283],[-2128.147,-217.3495],[-2118.137,194.3999],[-2108.127,-200.5035],[-2098.117,205.7527],[-2088.107,-198.7945],[-2078.097,214.1756],[-2068.087,-213.1991],[-2058.077,211.368],[-2048.068,-208.8045],[-2038.058,203.0671],[-2028.048,-196.8414],[-2018.038,207.95],[-2008.028,-212.5887],[-1998.018,204.654],[-1988.008,-204.1657],[-1977.998,222.7207],[-1967.988,-203.4333],[-1957.978,210.7576],[-1947.968,-211.0018],[-1937.959,195.3765],[-1927.949,-195.8648],[-1917.939,198.0621],[-1907.929,-205.2644],[-1897.919,195.2544],[-1887.909,-197.818],[-1877.899,201.7243],[-1867.889,-208.4382],[-1857.879,210.7576],[-1847.869,-205.9968],[-1837.859,200.9918],[-1827.85,-198.6725],[-1817.84,200.2594],[-1807.83,-205.8747],[-1797.82,203.3112],[-1787.81,-203.4333],[-1777.8,214.4198],[-1767.79,-212.4666],[-1757.78,209.1707],[-1747.77,-203.4333],[-1737.76,201.7243],[-1727.75,-197.4517],[-1717.741,201.9684],[-1707.731,-206.363],[-1697.721,209.9031],[-1687.711,-201.8463],[-1677.701,203.9216],[-1667.691,-210.8797],[-1657.681,209.0486],[-1647.671,-204.654],[-1637.661,203.3112],[-1627.651,-195.2544],[-1617.641,213.1991],[-1607.632,-201.9684],[-1597.622,204.0436],[-1587.612,-197.5738],[-1577.602,214.4198],[-1567.592,-214.9081],[-1557.582,205.7527],[-1547.572,-206.8513],[-1537.562,206.7292],[-1527.552,-201.7243],[-1517.542,210.6355],[-1507.532,-207.95],[-1497.523,204.7761],[-1487.513,-202.4567],[-1477.503,215.8846],[-1467.493,-217.1054],[-1457.483,209.4148],[-1447.473,-209.5369],[-1437.463,206.7292],[-1427.453,-209.781],[-1417.443,216.9833],[-1407.433,-212.2225],[-1397.423,208.072],[-1387.414,-209.781],[-1377.404,206.8513],[-1367.394,-208.072],[-1357.384,207.4617],[-1347.374,-208.4382],[-1337.364,196.7193],[-1327.354,-213.4432],[-1317.344,207.3396],[-1307.334,-205.1423],[-1297.324,210.6355],[-1287.314,-204.5319],[-1277.305,210.0252],[-1267.295,-211.1238],[-1257.285,210.1472],[-1247.275,-205.6306],[-1237.265,202.2126],[-1227.255,-208.9265],[-1217.245,208.8045],[-1207.235,-206.4851],[-1197.225,219.5468],[-1187.215,-215.0301],[-1177.205,213.1991],[-1167.196,-214.6639],[-1157.186,208.6824],[-1147.176,-205.7527],[-1137.166,210.5135],[-1127.156,-205.3864],[-1117.146,209.659],[-1107.136,-208.5603],[-1097.126,224.918],[-1087.116,-212.1004],[-1077.106,214.6639],[-1067.096,-215.1522],[-1057.087,207.4617],[-1047.077,-203.7995],[-1037.067,211.6121],[-1027.057,-215.0301],[-1017.047,223.331],[-1007.037,-213.9315],[-997.0271,225.2842],[-987.0171,-217.2274],[-977.0072,205.3864],[-966.9973,-215.3964],[-956.9874,205.9968],[-946.9775,-198.4283],[-936.9676,203.5554],[-926.9577,-216.495],[-916.9478,210.3914],[-906.9379,-217.8378],[-896.928,218.8144],[-886.918,-221.5],[-876.9081,197.6959],[-866.8982,-205.2644],[-856.8883,202.8229],[-846.8784,-211.0018],[-836.8685,214.5418],[-826.8586,-222.2324],[-816.8487,227.1153],[-806.8388,-216.8612],[-796.8289,218.4482],[-786.819,-215.6405],[-776.809,209.659],[-766.7991,-209.1707],[-756.7892,200.7477],[-746.7793,-210.6355],[-736.7694,214.5418],[-726.7595,-217.7157],[-716.7496,219.791],[-706.7397,-213.1991],[-696.7298,221.7441],[-686.7199,-222.1103],[-676.7099,198.7945],[-666.7,-210.7576],[-656.6901,212.9549],[-646.6802,-215.7626],[-636.6703,225.5283],[-626.6604,-217.2274],[-616.6505,230.5333],[-606.6406,-218.3261],[-596.6307,221.622],[-586.6208,-218.9364],[-576.6108,205.7527],[-566.6009,-213.077],[-556.591,216.495],[-546.5811,-218.8144],[-536.5712,223.4531],[-526.5613,-216.495],[-516.5514,222.8428],[-506.5415,-212.1004],[-496.5316,214.2977],[-486.5217,-224.1855],[-476.5117,207.2175],[-466.5018,-219.0585],[-456.4919,214.1756],[-446.482,-217.5937],[-436.4721,229.0684],[-426.4622,-211.6121],[-416.4523,221.5],[-406.4424,-217.2274],[-396.4325,208.6824],[-386.4226,-211.8563],[-376.4126,210.5135],[-366.4027,-210.7576],[-356.3928,216.7391],[-346.3829,-213.8094],[-336.373,220.7675],[-326.3631,-212.9549],[-316.3532,216.8612],[-306.3433,-212.3445],[-296.3334,204.7761],[-286.3235,-211.7342],[-276.3135,208.6824],[-266.3036,-219.4247],[-256.2937,216.2509],[-246.2838,-218.204],[-236.2739,219.913],[-226.264,-218.5702],[-216.2541,222.1103],[-206.2442,-224.5518],[-196.2343,222.5986],[-186.2244,-212.7108],[-176.2145,229.3126],[-166.2045,-220.0351],[-156.1946,216.495],[-146.1847,-218.9364],[-136.1748,220.5234],[-126.1649,-214.786],[-116.155,215.6405],[-106.1451,-225.0401],[-96.13517,227.2374],[-86.12526,-217.1054],[-76.11535,208.4382],[-66.10544,-217.4716],[-56.09553,223.6973],[-46.08562,-224.7959],[-36.07571,228.9464],[-26.0658,-222.1103],[-16.05589,224.5518],[-6.045985,-224.0635],[3.963925,222.3545],[13.97383,-211.368],[23.98374,212.4666],[33.99365,-210.7576],[44.00356,226.5049],[54.01347,-222.8428],[64.02338,230.5333],[74.03329,-222.2324],[84.0432,220.4013],[94.05311,-227.8477],[104.063,214.0536],[114.0729,-215.1522],[124.0828,223.8193],[134.0928,-221.7441],[144.1027,224.5518],[154.1126,-221.3779],[164.1225,228.8243],[174.1324,-224.3076],[184.1423,232.6085],[194.1522,-223.209],[204.1621,222.7207],[214.172,-217.8378],[224.1819,219.4247],[234.1919,-219.6689],[244.2018,228.0919],[254.2117,-224.4297],[264.2216,226.9932],[274.2315,-222.5986],[284.2414,227.7256],[294.2513,-219.913],[304.2612,223.331],[314.2711,-213.4432],[324.281,215.3964],[334.2909,-220.5234],[344.3009,228.5801],[354.3108,-220.4013],[364.3207,225.4063],[374.3306,-229.3126],[384.3405,232.1202],[394.3504,-220.4013],[404.3603,221.8662],[414.3702,-215.3964],[424.3801,221.9883],[434.39,-223.4531],[444.4,230.045],[454.4099,-228.2139],[464.4198,226.7491],[474.4297,-226.3828],[484.4396,223.8193],[494.4495,-222.9648],[504.4594,225.1621],[514.4693,-218.3261],[524.4792,221.8662],[534.4891,-227.6036],[544.4991,237.8576],[554.509,-229.4347],[564.5189,219.6689],[574.5288,-228.4581],[584.5387,213.077],[594.5486,-216.0067],[604.5585,221.9883],[614.5684,-207.3396],[624.5783,220.1572],[634.5882,-229.1905],[644.5982,230.1671],[654.6081,-231.9982],[664.618,224.7959],[674.6279,-228.9464],[684.6378,222.1103],[694.6477,-221.0117],[704.6576,233.5851],[714.6675,-217.4716],[724.6774,222.3545],[734.6873,-226.2608],[744.6973,232.4865],[754.7072,-233.9513],[764.7171,228.336],[774.727,-231.1437],[784.7369,227.6036],[794.7468,-224.918],[804.7567,230.045],[814.7666,-219.1806],[824.7765,227.7256],[834.7864,-225.5283],[844.7963,228.9464],[854.8063,-227.1153],[864.8162,224.6738],[874.8261,-230.1671],[884.836,228.5801],[894.8459,-225.7725],[904.8558,233.9513],[914.8657,-217.5937],[924.8756,230.8995],[934.8855,-232.6085],[944.8954,240.6653],[954.9054,-228.9464],[964.9153,234.9279],[974.9252,-227.2374],[984.9351,231.8761],[994.945,-232.4865],[1004.955,229.1905],[1014.965,-224.1855],[1024.975,231.3878],[1034.985,-235.05],[1044.995,236.8811],[1055.004,-227.4815],[1065.014,231.2657],[1075.024,-227.4815],[1085.034,228.4581],[1095.044,-233.463],[1105.054,238.1018],[1115.064,-220.0351],[1125.074,228.0919],[1135.084,-233.2189],[1145.094,233.2189],[1155.104,-224.6738],[1165.113,231.754],[1175.123,-226.0166],[1185.133,230.4112],[1195.143,-237.0031],[1205.153,230.045],[1215.163,-227.1153],[1225.173,236.6369],[1235.183,-242.8626],[1245.193,231.754],[1255.203,-229.6788],[1265.213,230.7774],[1275.222,-230.1671],[1285.232,231.5099],[1295.242,-230.7774],[1305.252,228.9464],[1315.262,-230.2892],[1325.272,232.9747],[1335.282,-239.5666],[1345.292,228.336],[1355.302,-227.7256],[1365.312,228.8243],[1375.322,-227.4815],[1385.331,232.2423],[1395.341,-240.4211],[1405.351,239.4446],[1415.361,-226.7491],[1425.371,234.8058],[1435.381,-240.5432],[1445.391,228.8243],[1455.401,-226.7491],[1465.411,4.577707],[1475.421,-1.770047],[1485.431,0.7934691],[1495.44,0.671397],[1505.45,0.4272526],[1515.46,0.7934691],[1525.47,1.281758],[1535.48,1.281758],[1545.49,1.281758],[1555.5,0.671397],[1565.51,0.9155413],[1575.52,0.7934691],[1585.53,0.4272526],[1595.54,0.7934691],[1605.549,1.281758],[1615.559,0.5493248],[1625.569,0.671397],[1635.579,0.7934691],[1645.589,0.9155413],[1655.599,1.281758],[1665.609,0.7934691],[1675.619,0.5493248],[1685.629,0.7934691],[1695.639,0.7934691],[1705.649,0.5493248],[1715.659,0.7934691],[1725.668,0.671397],[1735.678,0.671397],[1745.688,0.7934691],[1755.698,0.671397],[1765.708,0.671397],[1775.718,1.159686],[1785.728,0.7934691],[1795.738,0.9155413],[1805.748,0.4272526],[1815.758,0.7934691],[1825.768,1.281758],[1835.777,0.7934691],[1845.787,0.671397],[1855.797,0.7934691],[1865.807,0.5493248],[1875.817,0.1831083],[1885.827,1.037613],[1895.837,1.037613],[1905.847,0.3051804],[1915.857,1.037613],[1925.867,0.4272526],[1935.877,0.3051804],[1945.886,0.5493248],[1955.896,0.9155413],[1965.906,0.5493248],[1975.916,0.9155413],[1985.926,0.9155413],[1995.936,1.037613],[2005.946,0.671397],[2015.956,0.7934691],[2025.966,0.9155413],[2035.976,0.4272526],[2045.986,0.5493248],[2055.995,0.7934691],[2066.005,0.5493248],[2076.015,1.037613],[2086.025,0.7934691],[2096.035,0.7934691],[2106.045,0.5493248],[2116.055,0.7934691],[2126.065,0.671397],[2136.075,0.671397],[2146.085,0.671397],[2156.095,1.159686],[2166.104,1.037613],[2176.114,0.671397],[2186.124,0.671397],[2196.134,0.9155413],[2206.144,0.671397],[2216.154,0.4272526],[2226.164,0.671397],[2236.174,0.3051804],[2246.184,0.4272526],[2256.194,0.671397],[2266.204,0.9155413],[2276.213,0.5493248],[2286.223,0.671397],[2296.233,0.5493248],[2306.243,0.7934691],[2316.253,1.037613],[2326.263,0.5493248],[2336.273,1.159686],[2346.283,1.037613],[2356.293,0.5493248],[2366.303,0.3051804],[2376.313,0.671397],[2386.322,1.40383],[2396.332,0.5493248],[2406.342,0.5493248],[2416.352,0.3051804],[2426.362,1.037613],[2436.372,1.037613],[2446.382,0.671397],[2456.392,1.40383],[2466.402,0.7934691],[2476.412,0.671397],[2486.422,0.4272526],[2496.431,1.037613],[2506.441,0.9155413],[2516.451,1.40383],[2526.461,0.671397],[2536.471,0.671397],[2546.481,1.037613],[2556.491,1.037613],[2566.501,0.9155413],[2576.511,1.281758],[2586.521,0.7934691],[2596.531,0.3051804],[2606.54,1.281758],[2616.55,0.7934691],[2626.56,1.037613],[2636.57,0.671397],[2646.58,1.037613],[2656.59,0.3051804],[2666.6,0.671397],[2676.61,0.4272526],[2686.62,0.9155413],[2696.63,1.037613],[2706.64,1.159686],[2716.649,0.9155413],[2726.659,0.9155413],[2736.669,1.281758],[2746.679,0.1831083],[2756.689,0.671397],[2766.699,0.1831083],[2776.709,0.4272526],[2786.719,0.3051804],[2796.729,0.3051804],[2806.739,0.7934691],[2816.749,0.671397],[2826.758,0.3051804],[2836.768,1.037613],[2846.778,1.281758],[2856.788,0.5493248],[2866.798,0.5493248],[2876.808,0.4272526],[2886.818,1.40383],[2896.828,0.1831083],[2906.838,0.671397],[2916.848,0.1831083],[2926.858,1.281758],[2936.867,0.3051804],[2946.877,0.4272526],[2956.887,0.3051804],[2966.897,0.5493248],[2976.907,0.4272526],[2986.917,0.7934691],[2996.927,0.7934691],[3006.937,1.281758],[3016.947,0.4272526],[3026.957,1.037613],[3036.967,0.9155413],[3046.977,0.4272526],[3056.986,0.7934691],[3066.996,0.7934691],[3077.006,0.4272526],[3087.016,0.7934691],[3097.026,1.037613],[3107.036,0.3051804],[3117.046,0.9155413],[3127.056,0.5493248],[3137.066,0.671397],[3147.076,0.7934691],[3157.086,0.671397],[3167.095,1.159686],[3177.105,0.671397],[3187.115,0.7934691],[3197.125,0.3051804],[3207.135,0.9155413],[3217.145,0.9155413],[3227.155,1.281758],[3237.165,1.037613],[3247.175,0.7934691],[3257.185,0.671397],[3267.195,0.1831083],[3277.204,0.9155413],[3287.214,0.9155413],[3297.224,1.281758],[3307.234,1.281758],[3317.244,0.7934691],[3327.254,0.3051804],[3337.264,0.5493248],[3347.274,0.4272526],[3357.284,1.159686],[3367.294,0.7934691],[3377.304,0.3051804],[3387.313,1.037613],[3397.323,0.671397],[3407.333,0.1831083],[3417.343,0.5493248],[3427.353,0.7934691],[3437.363,0.671397],[3447.373,0.7934691],[3457.383,0.671397],[3467.393,0.5493248],[3477.403,0.5493248],[3487.413,0.7934691],[3497.422,0.3051804],[3507.432,0.3051804],[3517.442,1.525902],[3527.452,0.671397],[3537.462,0.7934691],[3547.472,0.9155413],[3557.482,1.281758],[3567.492,1.281758],[3577.502,0.671397],[3587.512,0.5493248],[3597.522,0.9155413],[3607.531,0.3051804],[3617.541,0.7934691],[3627.551,0.5493248],[3637.561,1.281758],[3647.571,0.5493248],[3657.581,1.40383],[3667.591,0.5493248],[3677.601,0.671397],[3687.611,0.671397],[3697.621,1.037613],[3707.631,1.037613],[3717.64,0.671397],[3727.65,0.5493248],[3737.66,1.159686],[3747.67,0.7934691],[3757.68,0.9155413],[3767.69,0.1831083],[3777.7,1.159686],[3787.71,1.525902],[3797.72,0.7934691],[3807.73,1.037613],[3817.74,0.671397],[3827.749,0.671397],[3837.759,1.281758],[3847.769,0.7934691],[3857.779,0.5493248],[3867.789,0.7934691],[3877.799,0.5493248],[3887.809,1.037613],[3897.819,1.037613],[3907.829,0.5493248],[3917.839,0.7934691],[3927.849,1.281758],[3937.858,0.671397],[3947.868,0.5493248],[3957.878,0.671397],[3967.888,1.159686],[3977.898,1.037613],[3987.908,1.159686],[3997.918,0.7934691],[4007.928,0.9155413],[4017.938,0.9155413],[4027.948,0.7934691],[4037.958,0.671397],[4047.967,0.3051804],[4057.977,0.9155413],[4067.987,0.671397],[4077.997,1.037613],[4088.007,0.4272526],[4098.017,0.671397],[4108.027,0.671397],[4118.037,0.9155413],[4128.047,0.5493248],[4138.057,1.281758],[4148.067,1.037613],[4158.076,0.671397],[4168.086,1.037613],[4178.096,0.671397],[4188.106,0.5493248],[4198.116,1.159686],[4208.126,1.159686],[4218.136,1.037613],[4228.146,1.037613],[4238.156,0.4272526],[4248.166,0.9155413],[4258.176,0.5493248],[4268.186,0.7934691],[4278.195,0.5493248],[4288.205,1.037613],[4298.215,1.525902],[4308.225,0.5493248],[4318.235,0.671397],[4328.245,0.9155413],[4338.255,0.1831083],[4348.265,0.5493248],[4358.275,0.1831083],[4368.285,0.9155413],[4378.295,0.671397],[4388.304,1.40383],[4398.314,0.3051804],[4408.324,0.5493248],[4418.334,0.7934691],[4428.344,0.5493248],[4438.354,0.671397],[4448.364,0.5493248],[4458.374,0.4272526],[4468.384,0.7934691],[4478.394,0.7934691],[4488.404,0.3051804],[4498.413,0.671397],[4508.423,0.7934691],[4518.433,1.40383],[4528.443,0.7934691],[4538.453,1.037613],[4548.463,0.5493248],[4558.473,0.671397],[4568.483,1.159686],[4578.493,1.037613],[4588.503,0.5493248],[4598.513,1.159686],[4608.522,1.159686],[4618.532,0.3051804],[4628.542,0.7934691],[4638.552,0.671397],[4648.562,0.4272526],[4658.572,0.9155413],[4668.582,0.7934691],[4678.592,0.9155413],[4688.602,0.4272526],[4698.612,1.037613],[4708.622,0.671397],[4718.631,0.7934691],[4728.641,0.7934691],[4738.651,0.3051804],[4748.661,0.5493248],[4758.671,0.7934691],[4768.681,0.3051804],[4778.691,0.9155413],[4788.701,0.9155413],[4798.711,0.4272526],[4808.721,0.4272526],[4818.731,0.9155413],[4828.74,1.037613],[4838.75,0.7934691],[4848.76,1.40383],[4858.77,1.159686],[4868.78,0.9155413],[4878.79,0.06103609],[4888.8,0.7934691],[4898.81,0.671397],[4908.82,1.037613],[4918.83,1.037613],[4928.84,0.9155413],[4938.849,0.5493248],[4948.859,0.3051804],[4958.869,0.7934691],[4968.879,0.671397],[4978.889,0.671397],[4988.899,0.4272526],[4998.909,0.671397],[5008.919,0.5493248],[5018.929,0.9155413],[5028.939,0.7934691],[5038.949,1.037613],[5048.958,0.5493248],[5058.968,0.671397],[5068.978,1.159686],[5078.988,0.5493248],[5088.998,0.1831083],[5099.008,1.647974],[5109.018,0.9155413],[5119.028,1.037613],[5129.038,0.7934691],[5139.048,1.037613],[5149.058,0.671397],[5159.067,0.671397],[5169.077,1.037613],[5179.087,1.037613],[5189.097,0.06103609],[5199.107,1.40383],[5209.117,0.9155413],[5219.127,1.037613],[5229.137,0.3051804],[5239.147,1.037613],[5249.157,0.5493248],[5259.167,0.9155413],[5269.176,1.037613],[5279.186,0.7934691],[5289.196,0.5493248],[5299.206,0.671397],[5309.216,1.037613],[5319.226,1.647974],[5329.236,1.037613],[5339.246,0.9155413],[5349.256,0.671397],[5359.266,1.159686],[5369.276,1.037613],[5379.285,0.671397],[5389.295,0.9155413],[5399.305,0.5493248],[5409.315,1.159686],[5419.325,1.281758],[5429.335,0.5493248],[5439.345,0.7934691],[5449.355,0.671397],[5459.365,0.4272526],[5469.375,0.7934691],[5479.385,0.3051804],[5489.395,0.3051804],[5499.404,0.5493248],[5509.414,1.037613],[5519.424,1.037613],[5529.434,1.037613],[5539.444,1.281758],[5549.454,0.671397],[5559.464,1.159686],[5569.474,0.9155413],[5579.484,0.9155413],[5589.494,0.9155413],[5599.504,1.159686],[5609.513,0.9155413],[5619.523,1.281758],[5629.533,0.4272526],[5639.543,0.7934691],[5649.553,0.06103609],[5659.563,1.037613],[5669.573,0.671397],[5679.583,0.7934691],[5689.593,0.5493248],[5699.603,0.1831083],[5709.613,0.3051804],[5719.622,1.281758],[5729.632,0.7934691],[5739.642,0.671397],[5749.652,1.037613],[5759.662,1.159686],[5769.672,1.281758],[5779.682,0.4272526],[5789.692,0.4272526],[5799.702,0.5493248],[5809.712,0.5493248],[5819.722,1.159686],[5829.731,0.1831083],[5839.741,0.9155413],[5849.751,0.7934691],[5859.761,1.037613],[5869.771,0.5493248],[5879.781,0.9155413],[5889.791,0.5493248],[5899.801,0.5493248],[5909.811,0.7934691],[5919.821,0.4272526],[5929.831,1.037613],[5939.84,0.9155413],[5949.85,0.7934691],[5959.86,0.9155413],[5969.87,0.1831083],[5979.88,1.159686],[5989.89,0.5493248],[5999.9,1.037613]]
@@ -1,4 +1,5 @@
1
1
  import type { WaveformData, WaveformPoint, WaveformSeries } from '../types'
2
+ import { recordedDampedPoints } from './recordedDampedWaveform'
2
3
 
3
4
  const POINT_COUNT = 1_000
4
5
  const START_TIME = -5
@@ -6,6 +7,7 @@ const END_TIME = 5
6
7
  const TWO_PI = Math.PI * 2
7
8
 
8
9
  type SignalGenerator = (time: number, noise: number) => number
10
+ type SignalSource = SignalGenerator | number[][]
9
11
  type ErrorGenerator = (
10
12
  time: number,
11
13
  value: number,
@@ -16,7 +18,7 @@ interface SimulatedSeriesDefinition extends Pick<
16
18
  WaveformSeries,
17
19
  'id' | 'trackId' | 'shotNo' | 'name' | 'unit' | 'color' | 'lineType' | 'pointType' | 'errorBar'
18
20
  > {
19
- signal: SignalGenerator
21
+ signal: SignalSource
20
22
  errors?: ErrorGenerator
21
23
  minimumX?: number
22
24
  }
@@ -30,14 +32,17 @@ function createSeededNoise(seed: number) {
30
32
  }
31
33
 
32
34
  function createPoints(
33
- signal: SignalGenerator,
35
+ signal: SignalSource,
34
36
  noise: () => number,
35
37
  errors?: ErrorGenerator,
36
38
  errorNoise: () => number = noise,
37
39
  ): WaveformPoint[] {
38
- return Array.from({ length: POINT_COUNT }, (_, index) => {
40
+ return Array.from({ length: Array.isArray(signal) ? signal.length : POINT_COUNT }, (_, index) => {
39
41
  const time = START_TIME + (index * (END_TIME - START_TIME)) / (POINT_COUNT - 1)
40
- const value = signal(time, noise())
42
+ const sampleNoise = noise()
43
+ // The recorded TXT uses milliseconds; chart coordinates are always seconds.
44
+ if (Array.isArray(signal)) return { x: signal[index][0] / 1_000, y: signal[index][1] }
45
+ const value = signal(time, sampleNoise)
41
46
  return {
42
47
  x: time,
43
48
  y: value,
@@ -98,15 +103,12 @@ const seriesDefinitions: SimulatedSeriesDefinition[] = [
98
103
  },
99
104
  {
100
105
  id: 'simulated-damped',
101
- shotNo: '13300',
106
+ shotNo: '13921',
102
107
  name: '阻尼振荡',
103
- unit: 'A',
108
+ unit: 'V',
104
109
  lineType: 'linear',
105
110
  pointType: 'none',
106
- signal: (time) => {
107
- const elapsed = time + 5
108
- return 2.4 * Math.exp(-elapsed * 0.28) * Math.sin(TWO_PI * 1.25 * elapsed)
109
- },
111
+ signal: recordedDampedPoints,
110
112
  },
111
113
  {
112
114
  id: 'simulated-step',
@@ -23,6 +23,7 @@ defineExpose({ resetViewport })
23
23
  v-model:hidden-series-ids="model.hiddenSeriesIds"
24
24
  :data="model.data"
25
25
  :min-visible-points="2"
26
+ :integer-zoom="model.integerZoom"
26
27
  :initial-x-domain="model.initialXDomain"
27
28
  :x-domain-strategy="{ type: 'integer-ms', includeExplicit: true }"
28
29
  :display-mode="model.displayMode"
@@ -66,6 +66,18 @@ const model = defineModel<DemoControlPanelModel>('model', { required: true })
66
66
  aria-label="零值参考线线宽"
67
67
  />
68
68
  </label>
69
+ <label class="frame-style-control">
70
+ <span>透明度</span>
71
+ <InputNumber
72
+ v-model:value="model.zeroLineOpacity"
73
+ :min="0"
74
+ :max="1"
75
+ :step="0.05"
76
+ :precision="2"
77
+ size="small"
78
+ aria-label="零值参考线透明度"
79
+ />
80
+ </label>
69
81
  <label class="frame-style-control">
70
82
  <span>线型</span>
71
83
  <Select
@@ -38,6 +38,10 @@ const model = defineModel<DemoControlPanelModel>('model', { required: true })
38
38
  <h2>视图</h2>
39
39
  <Button block aria-label="重置波形视图" @click="model.resetWaveformViewport"> 重置视图 </Button>
40
40
  <div class="auxiliary-style-controls" style="margin-top: 10px">
41
+ <label class="frame-style-control frame-style-control--switch">
42
+ <span>整数缩放</span>
43
+ <Switch v-model:checked="model.integerZoom" size="small" aria-label="整数缩放" />
44
+ </label>
41
45
  <label class="frame-style-control frame-style-control--switch">
42
46
  <span>数值 Tooltip</span>
43
47
  <Switch v-model:checked="model.showTooltip" size="small" aria-label="显示数值 Tooltip" />
package/src/demo/types.ts CHANGED
@@ -27,6 +27,7 @@ export interface DemoControlPanelModel {
27
27
  displayMode: WaveformDisplayMode
28
28
  overlayMode: WaveformOverlayMode
29
29
  showTooltip: boolean
30
+ integerZoom: boolean
30
31
  plotMarginTop: number
31
32
  plotMarginBottom: number
32
33
  cleanView: boolean
@@ -38,6 +39,7 @@ export interface DemoControlPanelModel {
38
39
  zeroLineVisible: boolean
39
40
  zeroLineColor: string
40
41
  zeroLineWidth: number
42
+ zeroLineOpacity: number
41
43
  zeroLineDash: string
42
44
  zeroLineDashOptions: Array<SelectOption<string>>
43
45
  rowCount: number
@@ -101,6 +103,7 @@ export interface DemoChartModel {
101
103
  cleanView: boolean
102
104
  presentationMode: boolean
103
105
  showTooltip: boolean
106
+ integerZoom: boolean
104
107
  plotMargin: WaveformPlotMargin
105
108
  zeroLine: WaveformZeroLineOptions
106
109
  frameWatermarkVisible: boolean
package/src/index.ts CHANGED
@@ -5,17 +5,21 @@
5
5
 
6
6
  // Vue 组件
7
7
  export { default as WaveformChart } from './components/WaveformChart.vue'
8
+ export type { WaveformChartProps } from './components/core/waveformChartTypes'
8
9
 
9
10
  // 类型定义
10
11
  export type {
11
12
  // 图表类型
12
13
  WaveformPoint,
13
14
  WaveformDisplayMode,
15
+ WaveformUnitDisplayMode,
16
+ WaveformLayoutPreset,
14
17
  WaveformOverlayMode,
15
18
  WaveformInteractionMode,
16
19
  WaveformXDomainStrategy,
17
20
  WaveformZoomIntentPayload,
18
21
  WaveformZoomEndPayload,
22
+ WaveformPanEndPayload,
19
23
  WaveformZoomResetPayload,
20
24
  WaveformAnnotationStyle,
21
25
  WaveformAnnotation,
package/src/styles.css CHANGED
@@ -329,7 +329,7 @@ body {
329
329
 
330
330
  .mobile-control-toggle {
331
331
  position: fixed;
332
- top: 10px;
332
+ top: 58px;
333
333
  left: 10px;
334
334
  z-index: 20;
335
335
  display: inline-flex;
@@ -339,7 +339,7 @@ body {
339
339
  .control-backdrop {
340
340
  position: fixed;
341
341
  inset: 0 0 0 min(300px, calc(100vw - 48px));
342
- z-index: 24;
342
+ z-index: 44;
343
343
  display: block;
344
344
  width: auto;
345
345
  height: 100%;
@@ -351,7 +351,7 @@ body {
351
351
  .control-panel {
352
352
  position: fixed;
353
353
  inset: 0 auto 0 0;
354
- z-index: 30;
354
+ z-index: 50;
355
355
  width: min(300px, calc(100vw - 48px));
356
356
  visibility: hidden;
357
357
  border-radius: 0 6px 6px 0;