waveform-analysis 0.1.50 → 0.1.52

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/dist/index.js CHANGED
@@ -2062,8 +2062,8 @@ function wr(e, t, n) {
2062
2062
  function Tr(e, t, n) {
2063
2063
  let r = xr(e), i = r[1] - r[0];
2064
2064
  if (!Number.isFinite(i) || i <= 0) return 0;
2065
- let a = Number.isFinite(n.minZoomSpan) && (n.minZoomSpan ?? 0) > 0 ? Math.min(i, n.minZoomSpan) : 0, o = Sr(n.minVisiblePoints), s = wr(t, r, o);
2066
- return a > 0 || o > 0 ? Math.max(a, s) : i / Rt.DEFAULT_MAX_SCALE;
2065
+ let a = Number.isFinite(n.minZoomSpan) && (n.minZoomSpan ?? 0) > 0 ? Math.min(i, n.minZoomSpan) : 0, o = Sr(n.minVisiblePoints), s = wr(t, r, o), c = Number(n.maxZoomScale), l = Number.isFinite(c) && c >= Rt.MIN_SCALE ? i / c : n.maxZoomScale !== null && a === 0 && o === 0 ? i / Rt.DEFAULT_MAX_SCALE : 0;
2066
+ return Math.max(a, s, l);
2067
2067
  }
2068
2068
  function Er(e, t, n, r) {
2069
2069
  if (r <= 0) return e;
@@ -2429,7 +2429,7 @@ function Mr(e) {
2429
2429
  let r = Math.abs(e[1] - e[0]);
2430
2430
  if (!Number.isFinite(r) || r <= 0) return Rt.MIN_SCALE;
2431
2431
  let i = Tr(e, n, t);
2432
- return Math.max(Rt.MIN_SCALE, i > 0 ? r / i : Rt.DEFAULT_MAX_SCALE);
2432
+ return Math.max(Rt.MIN_SCALE, i > 0 ? r / i : Infinity);
2433
2433
  }, R = (e, n, r, i) => Or(Dr(e.rescaleX(U(n, [0, r])).domain(), n, i, t), n, r), z = (e) => {
2434
2434
  let n = Number(t.minVisiblePoints);
2435
2435
  return On(e.seriesList, e.xScale.domain(), Number.isFinite(n) && n > 0 ? Math.ceil(n) + 1 : n);
@@ -2535,6 +2535,7 @@ function Pr(e) {
2535
2535
  z,
2536
2536
  () => t.minZoomSpan,
2537
2537
  () => t.minVisiblePoints,
2538
+ () => t.maxZoomScale,
2538
2539
  () => t.initialXDomain,
2539
2540
  () => t.initialXDomains,
2540
2541
  () => t.xDomainStrategy,
@@ -5533,6 +5534,7 @@ var po = ["clip-path"], mo = ["data-series-id", "data-series-name"], ho = [
5533
5534
  },
5534
5535
  minZoomSpan: {},
5535
5536
  minVisiblePoints: { default: 0 },
5537
+ maxZoomScale: {},
5536
5538
  initialXDomain: {},
5537
5539
  initialXDomains: {},
5538
5540
  xDomainStrategy: { default: () => ({ type: "data" }) },
@@ -334,6 +334,7 @@ export declare function useWaveformChartController(props: ResolvedWaveformChartP
334
334
  pannable: boolean;
335
335
  minZoomSpan?: number | undefined;
336
336
  minVisiblePoints: number;
337
+ maxZoomScale?: number | null | undefined;
337
338
  initialXDomains?: Record<string, [number, number]> | undefined;
338
339
  xDomainStrategy: import("../..").WaveformXDomainStrategy;
339
340
  yDomain?: [number, number] | undefined;
@@ -14,6 +14,7 @@ export interface WaveformChartProps {
14
14
  pannable?: boolean;
15
15
  minZoomSpan?: number;
16
16
  minVisiblePoints?: number;
17
+ maxZoomScale?: number | null;
17
18
  initialXDomain?: [number, number];
18
19
  initialXDomains?: Record<string, [number, number]>;
19
20
  xDomainStrategy?: WaveformXDomainStrategy;
@@ -9,6 +9,7 @@ export type ZoomSeriesGroup = readonly PointSeriesSource[];
9
9
  interface ZoomConstraintOptions {
10
10
  minZoomSpan?: number;
11
11
  minVisiblePoints?: number;
12
+ maxZoomScale?: number | null;
12
13
  }
13
14
  export declare function resolveMinimumZoomSpan(boundary: [number, number], groups: readonly ZoomSeriesGroup[], options: ZoomConstraintOptions): number;
14
15
  export declare function constrainZoomDomain(domain: [number, number], boundary: [number, number], groups: readonly ZoomSeriesGroup[], options: ZoomConstraintOptions): [number, number];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waveform-analysis",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -213,6 +213,7 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
213
213
  isPresentationMode,
214
214
  () => props.minZoomSpan,
215
215
  () => props.minVisiblePoints,
216
+ () => props.maxZoomScale,
216
217
  () => props.initialXDomain,
217
218
  () => props.initialXDomains,
218
219
  () => props.xDomainStrategy,
@@ -35,6 +35,7 @@ export interface WaveformChartProps {
35
35
  pannable?: boolean
36
36
  minZoomSpan?: number
37
37
  minVisiblePoints?: number
38
+ maxZoomScale?: number | null
38
39
  initialXDomain?: [number, number]
39
40
  initialXDomains?: Record<string, [number, number]>
40
41
  xDomainStrategy?: WaveformXDomainStrategy
@@ -231,7 +231,7 @@ export function useWaveformZoom(context: ZoomContext) {
231
231
  const minimumSpan = resolveMinimumZoomSpan(domain, groups, props)
232
232
  return Math.max(
233
233
  ZOOM_CONSTRAINTS.MIN_SCALE,
234
- minimumSpan > 0 ? domainSpan / minimumSpan : ZOOM_CONSTRAINTS.DEFAULT_MAX_SCALE,
234
+ minimumSpan > 0 ? domainSpan / minimumSpan : Number.POSITIVE_INFINITY,
235
235
  )
236
236
  }
237
237
  const constrainTransform = (
@@ -14,6 +14,7 @@ export type ZoomSeriesGroup = readonly PointSeriesSource[]
14
14
  interface ZoomConstraintOptions {
15
15
  minZoomSpan?: number
16
16
  minVisiblePoints?: number
17
+ maxZoomScale?: number | null
17
18
  }
18
19
 
19
20
  const xValueCache = new WeakMap<object, Map<string, number[]>>()
@@ -80,10 +81,14 @@ export function resolveMinimumZoomSpan(
80
81
  : 0
81
82
  const required = resolveRequiredPointCount(options.minVisiblePoints)
82
83
  const pointSpan = minimumPointSpan(groups, normalized, required)
83
- if (configuredSpan > 0 || required > 0) {
84
- return Math.max(configuredSpan, pointSpan)
85
- }
86
- return boundarySpan / ZOOM_CONSTRAINTS.DEFAULT_MAX_SCALE
84
+ const configuredScale = Number(options.maxZoomScale)
85
+ const scaleSpan =
86
+ Number.isFinite(configuredScale) && configuredScale >= ZOOM_CONSTRAINTS.MIN_SCALE
87
+ ? boundarySpan / configuredScale
88
+ : options.maxZoomScale !== null && configuredSpan === 0 && required === 0
89
+ ? boundarySpan / ZOOM_CONSTRAINTS.DEFAULT_MAX_SCALE
90
+ : 0
91
+ return Math.max(configuredSpan, pointSpan, scaleSpan)
87
92
  }
88
93
 
89
94
  function expandToMinimumPoints(
@@ -65,10 +65,10 @@ function dispatchBox(
65
65
  }
66
66
 
67
67
  describe('WaveformChart point-aware zoom constraints', () => {
68
- it('wheel-zooms 1,200 samples to two distinct X values, stops, and still zooms out', async () => {
68
+ it('zooms to two distinct X values when the scale limit is disabled', async () => {
69
69
  const wrapper = await mountSizedChart(
70
70
  { kind: 'points', points: regularPoints },
71
- { minVisiblePoints: 2 },
71
+ { minVisiblePoints: 2, maxZoomScale: null },
72
72
  )
73
73
  const { overlay, width, height } = prepareOverlay(
74
74
  wrapper,
@@ -151,7 +151,7 @@ describe('WaveformChart point-aware zoom constraints', () => {
151
151
  expect(visibleXCount(constrainedDomain)).toBe(2)
152
152
  })
153
153
 
154
- it('retains the default 40x maximum when no explicit limit is configured', async () => {
154
+ it('retains the backwards-compatible default maximum zoom scale', async () => {
155
155
  const wrapper = await mountSizedChart({ kind: 'points', points: regularPoints })
156
156
  const { overlay, width, height } = prepareOverlay(
157
157
  wrapper,
@@ -163,6 +163,66 @@ describe('WaveformChart point-aware zoom constraints', () => {
163
163
  expect(domain[1] - domain[0]).toBeCloseTo(1_199 / 40)
164
164
  })
165
165
 
166
+ it('honors an explicit maximum zoom scale', async () => {
167
+ const wrapper = await mountSizedChart(
168
+ { kind: 'points', points: regularPoints },
169
+ { maxZoomScale: 20 },
170
+ )
171
+ const { overlay, width, height } = prepareOverlay(
172
+ wrapper,
173
+ '.waveform-chart__overlay--independent',
174
+ )
175
+
176
+ await dispatchWheel(overlay, width, height, -4_000)
177
+ const domain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
178
+ expect(domain[1] - domain[0]).toBeCloseTo(1_199 / 20)
179
+ })
180
+
181
+ it('disables the compatibility scale limit when configured with null', async () => {
182
+ const wrapper = await mountSizedChart(
183
+ { kind: 'points', points: regularPoints },
184
+ { maxZoomScale: null },
185
+ )
186
+ const { overlay, width, height } = prepareOverlay(
187
+ wrapper,
188
+ '.waveform-chart__overlay--independent',
189
+ )
190
+
191
+ await dispatchWheel(overlay, width, height, -4_000)
192
+ const domain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
193
+ expect(domain[1] - domain[0]).toBeLessThan(1_199 / 40)
194
+ })
195
+
196
+ it('falls back to the compatibility limit for an invalid maximum scale', async () => {
197
+ const wrapper = await mountSizedChart(
198
+ { kind: 'points', points: regularPoints },
199
+ { maxZoomScale: 0 },
200
+ )
201
+ const { overlay, width, height } = prepareOverlay(
202
+ wrapper,
203
+ '.waveform-chart__overlay--independent',
204
+ )
205
+
206
+ await dispatchWheel(overlay, width, height, -4_000)
207
+ const domain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
208
+ expect(domain[1] - domain[0]).toBeCloseTo(1_199 / 40)
209
+ })
210
+
211
+ it('uses the strictest configured zoom constraint', async () => {
212
+ const wrapper = await mountSizedChart(
213
+ { kind: 'points', points: regularPoints },
214
+ { minZoomSpan: 50, minVisiblePoints: 2, maxZoomScale: 40 },
215
+ )
216
+ const { overlay, width, height } = prepareOverlay(
217
+ wrapper,
218
+ '.waveform-chart__overlay--independent',
219
+ )
220
+
221
+ await dispatchWheel(overlay, width, height, -4_000)
222
+ const domain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
223
+ expect(domain[1] - domain[0]).toBeCloseTo(50)
224
+ })
225
+
166
226
  it('retains two endpoint samples while replacing an independent data window', async () => {
167
227
  const sourcePoints = Array.from({ length: 1_000 }, (_, index) => ({
168
228
  x: -5 + (index * 10) / 999,
@@ -68,6 +68,7 @@ const mode = ref<WaveformSamplingMode>('auto')
68
68
  const strategy = ref<WaveformSamplingStrategy>('peak')
69
69
  const autoThreshold = ref(1_000)
70
70
  const maxPointsPerPixel = ref(3)
71
+ const minVisiblePoints = ref(2)
71
72
  const diagnostics = reactive<Record<string, WaveformSamplingDiagnostics | undefined>>({})
72
73
 
73
74
  const rendering = computed<WaveformRenderingOptions>(() => ({
@@ -135,6 +136,10 @@ function pointCount(value: number | undefined) {
135
136
  size="small"
136
137
  />
137
138
  </label>
139
+ <label>
140
+ <span>最少可见点</span>
141
+ <InputNumber v-model:value="minVisiblePoints" :min="2" :max="1000" :step="1" size="small" />
142
+ </label>
138
143
  </section>
139
144
 
140
145
  <section class="sampling-demo__workspace">
@@ -144,6 +149,8 @@ function pointCount(value: number | undefined) {
144
149
  :rendering="rendering"
145
150
  :grid="{ rowCount: 1, columnCount: 1, showPagination: false }"
146
151
  :legend="{ position: 'top-right', orientation: 'vertical' }"
152
+ :max-zoom-scale="null"
153
+ :min-visible-points="minVisiblePoints"
147
154
  :title="{ visible: true, text: '多系列采样与缓存诊断', align: 'left' }"
148
155
  x-label="时间(s)"
149
156
  time-unit="s"