Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54477ecbbd | ||
|
|
d349220395 | ||
|
|
81f36bde71 |
@@ -15,12 +15,13 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
server_url="${{ gitea.server_url }}"
|
||||
repository_url="${server_url%/}/${{ gitea.repository }}.git"
|
||||
tag_name="${{ gitea.ref_name }}"
|
||||
git init .
|
||||
git remote add origin "$repository_url"
|
||||
git fetch --depth 1 origin "refs/tags/$tag_name:refs/tags/$tag_name"
|
||||
git checkout --detach "$tag_name^{commit}"
|
||||
archive_url="${server_url%/}/api/v1/repos/${{ gitea.repository }}/archive/$tag_name.tar.gz"
|
||||
curl --fail --show-error --silent --location "$archive_url" --output source.tar.gz
|
||||
mkdir source
|
||||
tar -xzf source.tar.gz --strip-components=1 -C source
|
||||
cp -a source/. .
|
||||
rm -rf source source.tar.gz
|
||||
|
||||
- name: Set up pnpm
|
||||
run: |
|
||||
@@ -214,7 +215,7 @@ jobs:
|
||||
: "${RELEASE_TOKEN:?RELEASE_TOKEN is required}"
|
||||
server_url="${{ gitea.server_url }}"
|
||||
api_url="$server_url/api/v1/repos/${{ gitea.repository }}/releases"
|
||||
target_commitish="$(git rev-parse HEAD)"
|
||||
target_commitish="$TAG_NAME"
|
||||
|
||||
node - "$TAG_NAME" "$PACKAGE_VERSION" "$target_commitish" "$IS_PRERELEASE" > release.json <<'NODE'
|
||||
const [tagName, packageVersion, targetCommitish, prerelease] = process.argv.slice(2)
|
||||
|
||||
23
README.md
23
README.md
@@ -111,6 +111,7 @@ const data = ref<WaveformData>({
|
||||
| `minVisiblePoints` | `number` | `0` | 缩放后至少保留的不同 X 坐标数 |
|
||||
| `initialXDomain` | `[number, number]` | 未设置 | 所有图框的初始 X 范围 |
|
||||
| `initialXDomains` | `Record<string, [number, number]>` | 未设置 | 按 track/series ID 配置初始范围 |
|
||||
| `xDomainStrategy` | `WaveformXDomainStrategy` | `{ type: 'data' }` | 自动 X 轴视口范围策略 |
|
||||
| `yDomain` | `[number, number]` | 未设置 | 所有波形的固定 Y 轴范围 |
|
||||
| `yDomains` | `Record<string, [number, number]>` | 未设置 | 按 track/series ID 配置固定范围 |
|
||||
| `grid` | `WaveformGridOptions` | `{ rowCount: 2, columnCount: 1, showPagination: true }` | 网格和分页 |
|
||||
@@ -129,7 +130,7 @@ const data = ref<WaveformData>({
|
||||
|
||||
所有公开类型均可从包入口导入,例如 `WaveformData`、`WaveformSeries`、
|
||||
`WaveformAnnotation`、`WaveformLineStyle`、`WaveformRenderingOptions`、
|
||||
`WaveformAxesOptions`、`WaveformXAxisLabelFormatter`、`WaveformZeroLineOptions`、
|
||||
`WaveformAxesOptions`、`WaveformXAxisLabelFormatter`、`WaveformXDomainStrategy`、`WaveformZeroLineOptions`、
|
||||
`WaveformGridOptions` 和 `WaveformGridTrackLines`。
|
||||
|
||||
### 数据结构
|
||||
@@ -252,6 +253,26 @@ X 轴且包含多个轨道时使用按稳定 track ID 索引的 `yRanges`。平
|
||||
重置组件内部缩放并触发 `zoom-reset`;调用方应在事件中取消区间请求并恢复首次完整数据。
|
||||
外部重置按钮也可以通过模板引用调用组件公开的 `resetViewport()` 方法,然后执行相同的数据恢复逻辑。
|
||||
|
||||
没有显式配置初始范围时,可以通过 `xDomainStrategy` 将数据范围扩展为便于阅读的视口端点。
|
||||
默认的 `{ type: 'data' }` 保持数据最小值和最大值不变;`type: 'nice'` 使用固定刻度数量计算
|
||||
易读边界,且只扩展视口,不修改原始点位、tooltip、标注或缩放事件值:
|
||||
|
||||
```vue
|
||||
<WaveformChart
|
||||
:data="chartData"
|
||||
:x-domain-strategy="{ type: 'nice', bounds: 'end', tickCount: 10, includeExplicit: true }"
|
||||
/>
|
||||
```
|
||||
|
||||
例如秒坐标数据范围为 `[0, 4.999999]` 且 `timeUnit='ms'` 时,上述配置会使用
|
||||
`[0, 5]` 作为初始及重置视口,两端 label 显示 `0` 和 `5000`。`bounds: 'end'`
|
||||
只扩展右端;默认的 `bounds: 'both'`
|
||||
会同时扩展两端。`tickCount` 默认为 `10`,只参与边界计算,不随组件宽度变化。
|
||||
`initialXDomains`、`initialXDomain` 的显式配置默认保持原值;仅当 `includeExplicit: true` 时
|
||||
也应用 nice 扩展。独立模式在未配置显式范围时
|
||||
按图框分别计算,共享 X 轴模式则合并所有可见图框后计算。所有范围仍使用原始秒坐标,
|
||||
`timeUnit` 只影响显示。
|
||||
|
||||
独立坐标模式下,回填响应应只替换 `seriesIds` 对应的系列,并调用
|
||||
`resetViewport(trackIndex)`;其他图框的数据和缩放状态应保持不变。独立模式下双击图框触发的
|
||||
`zoom-reset` payload 会包含该图框的 `trackIndex` 和 `seriesIds`;共享 X 范围模式的 payload
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "waveform-analysis",
|
||||
"version": "0.1.32",
|
||||
"version": "0.1.35",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
|
||||
@@ -16,6 +16,7 @@ const props = withDefaults(defineProps<WaveformChartProps>(), {
|
||||
zoomable: true,
|
||||
pannable: false,
|
||||
minVisiblePoints: 0,
|
||||
xDomainStrategy: () => ({ type: 'data' }),
|
||||
timeUnit: 'ms',
|
||||
frameNumber: undefined,
|
||||
annotations: () => [],
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
WaveformDisplayMode,
|
||||
WaveformOverlayMode,
|
||||
WaveformPoint,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformXAxisLabelFormatter,
|
||||
} from '../../types'
|
||||
import { buildMinorTicks, formatXAxisLabel } from '../../utils'
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
} from './grid'
|
||||
import { axisTextMetrics, resolveYAxisSeriesGroups } from './layout'
|
||||
import type { DisplaySeries, DisplayTrack, TrackLayout, WaveformYAxisLayout } from './types'
|
||||
import { applyXDomainStrategy } from './xDomain'
|
||||
import {
|
||||
Y_AXIS_LABEL_BAND_WIDTH,
|
||||
Y_AXIS_LABEL_GAP,
|
||||
@@ -46,6 +48,7 @@ export interface BuildTrackLayoutsOptions {
|
||||
sharedZoomDomain: [number, number]
|
||||
initialXDomain?: [number, number]
|
||||
initialXDomains?: Record<string, [number, number]>
|
||||
xDomainStrategy?: WaveformXDomainStrategy
|
||||
fixedYDomain?: [number, number]
|
||||
fixedYDomains?: Record<string, [number, number]>
|
||||
yDomains?: Record<string, [number, number]>
|
||||
@@ -57,6 +60,21 @@ export interface BuildTrackLayoutsOptions {
|
||||
showCompactEmptyTracks: boolean
|
||||
}
|
||||
|
||||
function resolveIndependentXDomain(
|
||||
track: DisplayTrack,
|
||||
seriesId: string,
|
||||
options: BuildTrackLayoutsOptions,
|
||||
): [number, number] {
|
||||
const strategy = options.xDomainStrategy ?? { type: 'data' }
|
||||
const explicitDomain =
|
||||
options.initialXDomains?.[track.id] ??
|
||||
options.initialXDomains?.[seriesId] ??
|
||||
options.initialXDomain
|
||||
return explicitDomain
|
||||
? applyXDomainStrategy(explicitDomain, strategy, true)
|
||||
: applyXDomainStrategy(track.xDomain, strategy)
|
||||
}
|
||||
|
||||
export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayout[] {
|
||||
const visibleCells = options.cells.map((cell) => ({ ...cell, hasSeries: Boolean(cell.series) }))
|
||||
const bottomCells = getBottomRowCellIndexes(visibleCells, options.grid.columnCount)
|
||||
@@ -88,13 +106,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
||||
const series = displayTrack.visibleSeries[0] ?? displayTrack.series[0] ?? emptySeries
|
||||
const baseXScale =
|
||||
options.displayMode === 'independent'
|
||||
? scaleLinear(
|
||||
options.initialXDomains?.[displayTrack.id] ??
|
||||
options.initialXDomains?.[series.id] ??
|
||||
options.initialXDomain ??
|
||||
displayTrack.xDomain,
|
||||
[0, cell.width],
|
||||
)
|
||||
? scaleLinear(resolveIndependentXDomain(displayTrack, series.id, options), [0, cell.width])
|
||||
: scaleLinear(options.sharedZoomDomain, [0, cell.width])
|
||||
const transform =
|
||||
options.displayMode === 'independent'
|
||||
|
||||
@@ -204,6 +204,7 @@ export function useWaveformChartLifecycle(context: LifecycleContext) {
|
||||
() => props.minVisiblePoints,
|
||||
() => props.initialXDomain,
|
||||
() => props.initialXDomains,
|
||||
() => props.xDomainStrategy,
|
||||
() => props.displayMode,
|
||||
() => chartTracks.value.length,
|
||||
currentPage,
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
import type { DisplaySeries, DisplayTrack, TrackLayout } from './types'
|
||||
import type { PreparedWaveformSeries } from './useWaveformData'
|
||||
import type { ResolvedWaveformChartProps } from './waveformChartTypes'
|
||||
import { applyXDomainStrategy } from './xDomain'
|
||||
import type { useWaveformAnnotationInteraction } from '../annotation'
|
||||
|
||||
interface LayoutContext {
|
||||
@@ -224,9 +225,13 @@ export function useWaveformLayout(context: LayoutContext) {
|
||||
Number.isFinite(domain[1]) &&
|
||||
domain[0] !== domain[1]
|
||||
) {
|
||||
return domain[0] < domain[1] ? domain : [domain[1], domain[0]]
|
||||
return applyXDomainStrategy(
|
||||
domain[0] < domain[1] ? domain : [domain[1], domain[0]],
|
||||
props.xDomainStrategy,
|
||||
true,
|
||||
)
|
||||
}
|
||||
return sharedXDomain.value
|
||||
return applyXDomainStrategy(sharedXDomain.value, props.xDomainStrategy)
|
||||
})
|
||||
const resolveInitialTrackDomain = (track: TrackLayout): [number, number] => {
|
||||
const configuredDomain =
|
||||
@@ -239,11 +244,18 @@ export function useWaveformLayout(context: LayoutContext) {
|
||||
Number.isFinite(configuredDomain[1]) &&
|
||||
configuredDomain[0] !== configuredDomain[1]
|
||||
) {
|
||||
return configuredDomain[0] < configuredDomain[1]
|
||||
? configuredDomain
|
||||
: [configuredDomain[1], configuredDomain[0]]
|
||||
return applyXDomainStrategy(
|
||||
configuredDomain[0] < configuredDomain[1]
|
||||
? configuredDomain
|
||||
: [configuredDomain[1], configuredDomain[0]],
|
||||
props.xDomainStrategy,
|
||||
true,
|
||||
)
|
||||
}
|
||||
return paddedDomain(track.seriesList.flatMap((series) => series.xDomain))
|
||||
return applyXDomainStrategy(
|
||||
paddedDomain(track.seriesList.flatMap((series) => series.xDomain)),
|
||||
props.xDomainStrategy,
|
||||
)
|
||||
}
|
||||
const sharedZoomDomain = computed(
|
||||
() =>
|
||||
@@ -272,6 +284,7 @@ export function useWaveformLayout(context: LayoutContext) {
|
||||
sharedZoomDomain: sharedZoomDomain.value,
|
||||
initialXDomain: props.initialXDomain ? initialXDomain.value : undefined,
|
||||
initialXDomains: props.initialXDomains,
|
||||
xDomainStrategy: props.xDomainStrategy,
|
||||
fixedYDomain: props.yDomain,
|
||||
fixedYDomains: props.yDomains,
|
||||
yDomains:
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
WaveformPoint,
|
||||
WaveformRenderingOptions,
|
||||
WaveformTitleOptions,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformZeroLineOptions,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
@@ -33,6 +34,7 @@ export interface WaveformChartProps {
|
||||
minVisiblePoints?: number
|
||||
initialXDomain?: [number, number]
|
||||
initialXDomains?: Record<string, [number, number]>
|
||||
xDomainStrategy?: WaveformXDomainStrategy
|
||||
yDomain?: [number, number]
|
||||
yDomains?: Record<string, [number, number]>
|
||||
timeUnit?: 's' | 'ms'
|
||||
@@ -63,6 +65,7 @@ type DefaultedProp =
|
||||
| 'zoomable'
|
||||
| 'pannable'
|
||||
| 'minVisiblePoints'
|
||||
| 'xDomainStrategy'
|
||||
| 'timeUnit'
|
||||
| 'annotations'
|
||||
| 'annotationsVisible'
|
||||
|
||||
28
src/components/core/xDomain.test.ts
Normal file
28
src/components/core/xDomain.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { applyXDomainStrategy } from './xDomain'
|
||||
|
||||
describe('applyXDomainStrategy', () => {
|
||||
it('keeps the exact data domain by default', () => {
|
||||
expect(applyXDomainStrategy([0, 4999.999], { type: 'data' })).toEqual([0, 4999.999])
|
||||
})
|
||||
|
||||
it('expands both bounds to stable nice values', () => {
|
||||
expect(applyXDomainStrategy([123, 456], { type: 'nice' })).toEqual([100, 500])
|
||||
})
|
||||
|
||||
it('can expand only the end bound', () => {
|
||||
expect(applyXDomainStrategy([123, 456], { type: 'nice', bounds: 'end' })).toEqual([123, 500])
|
||||
})
|
||||
|
||||
it('keeps explicit domains exact unless they are included', () => {
|
||||
expect(applyXDomainStrategy([123, 456], { type: 'nice' }, true)).toEqual([123, 456])
|
||||
expect(applyXDomainStrategy([123, 456], { type: 'nice', includeExplicit: true }, true)).toEqual(
|
||||
[100, 500],
|
||||
)
|
||||
})
|
||||
|
||||
it('falls back to the default tick count for invalid values', () => {
|
||||
expect(applyXDomainStrategy([0, 4999.999], { type: 'nice', tickCount: 0 })).toEqual([0, 5000])
|
||||
})
|
||||
})
|
||||
25
src/components/core/xDomain.ts
Normal file
25
src/components/core/xDomain.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { scaleLinear } from 'd3'
|
||||
|
||||
import type { WaveformXDomainStrategy } from '../../types'
|
||||
|
||||
const DEFAULT_NICE_TICK_COUNT = 10
|
||||
|
||||
function resolveTickCount(value: number | undefined): number {
|
||||
if (!Number.isFinite(value) || (value ?? 0) < 1) return DEFAULT_NICE_TICK_COUNT
|
||||
return Math.max(1, Math.trunc(value as number))
|
||||
}
|
||||
|
||||
/** Derives a viewport domain without changing any source coordinates. */
|
||||
export function applyXDomainStrategy(
|
||||
domain: [number, number],
|
||||
strategy: WaveformXDomainStrategy,
|
||||
explicit = false,
|
||||
): [number, number] {
|
||||
if (strategy.type !== 'nice' || (explicit && !strategy.includeExplicit)) return [...domain]
|
||||
|
||||
const niceDomain = scaleLinear()
|
||||
.domain(domain)
|
||||
.nice(resolveTickCount(strategy.tickCount))
|
||||
.domain() as [number, number]
|
||||
return strategy.bounds === 'end' ? [domain[0], niceDomain[1]] : niceDomain
|
||||
}
|
||||
@@ -9,6 +9,7 @@ export type {
|
||||
WaveformDisplayMode,
|
||||
WaveformOverlayMode,
|
||||
WaveformInteractionMode,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
WaveformAnnotationStyle,
|
||||
|
||||
@@ -9,6 +9,7 @@ export type {
|
||||
WaveformDisplayMode,
|
||||
WaveformOverlayMode,
|
||||
WaveformInteractionMode,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformAnnotationStyle,
|
||||
WaveformAnnotation,
|
||||
WaveformRenderingOptions,
|
||||
|
||||
@@ -5,6 +5,13 @@ import { flushAnimationFrames } from '../../test/setup'
|
||||
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
||||
|
||||
describe('WaveformChart viewport reset', () => {
|
||||
const niceExplicitStrategy = {
|
||||
type: 'nice' as const,
|
||||
bounds: 'end' as const,
|
||||
tickCount: 10,
|
||||
includeExplicit: true,
|
||||
}
|
||||
|
||||
it('resets a shared viewport on double-click and emits a global payload', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
@@ -111,4 +118,32 @@ describe('WaveformChart viewport reset', () => {
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--start')[0].text()).toBe('0')
|
||||
expect(wrapper.findAll('.waveform-chart__axis-endpoint--end')[0].text()).toBe('1000')
|
||||
})
|
||||
|
||||
it('resets shared and independent explicit domains to their included nice bounds', async () => {
|
||||
const shared = await mountSizedChart(
|
||||
{
|
||||
kind: 'points',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 4.999999, y: 1 },
|
||||
],
|
||||
},
|
||||
{ initialXDomain: [0, 4.999999], xDomainStrategy: niceExplicitStrategy },
|
||||
)
|
||||
const independent = await mountSizedChart(gridSeries(2), {
|
||||
displayMode: 'independent',
|
||||
initialXDomains: { 'channel-0': [0, 4.999999] },
|
||||
xDomainStrategy: niceExplicitStrategy,
|
||||
})
|
||||
|
||||
;(shared.vm as unknown as { resetViewport: () => void }).resetViewport()
|
||||
;(independent.vm as unknown as { resetViewport: () => void }).resetViewport()
|
||||
await flushPromises()
|
||||
|
||||
expect(shared.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(shared.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
||||
const firstTrack = independent.findAll('.waveform-chart__track')[0]
|
||||
expect(firstTrack.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(firstTrack.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
||||
})
|
||||
})
|
||||
|
||||
96
src/components/waveformChartCases/xDomainStrategy.test.ts
Normal file
96
src/components/waveformChartCases/xDomainStrategy.test.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
||||
|
||||
describe('WaveformChart x domain strategy', () => {
|
||||
it('expands automatic x domains without changing source seconds', async () => {
|
||||
const data = {
|
||||
kind: 'points' as const,
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 4.999999, y: 1 },
|
||||
],
|
||||
}
|
||||
const wrapper = await mountSizedChart(data, {
|
||||
timeUnit: 'ms',
|
||||
xDomainStrategy: { type: 'nice', bounds: 'end' },
|
||||
})
|
||||
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
||||
expect(data.points[1]?.x).toBe(4.999999)
|
||||
})
|
||||
|
||||
it('keeps explicit initial x domains exact by default', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
kind: 'points',
|
||||
points: [
|
||||
{ x: 123, y: 0 },
|
||||
{ x: 456, y: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
timeUnit: 's',
|
||||
initialXDomain: [120, 460],
|
||||
xDomainStrategy: { type: 'nice' },
|
||||
},
|
||||
)
|
||||
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('120')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('460')
|
||||
})
|
||||
|
||||
it('keeps explicit per-track initial x domains exact by default', async () => {
|
||||
const wrapper = await mountSizedChart(gridSeries(1), {
|
||||
displayMode: 'independent',
|
||||
initialXDomains: { 'channel-0': [0, 4.999999] },
|
||||
xDomainStrategy: { type: 'nice', bounds: 'end' },
|
||||
})
|
||||
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('4999.999')
|
||||
})
|
||||
|
||||
it('includes an explicit shared initial x domain when requested', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
kind: 'points',
|
||||
points: [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 4.999999, y: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
initialXDomain: [0, 4.999999],
|
||||
xDomainStrategy: {
|
||||
type: 'nice',
|
||||
bounds: 'end',
|
||||
tickCount: 10,
|
||||
includeExplicit: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
||||
})
|
||||
|
||||
it('includes explicit per-track initial x domains in independent mode', async () => {
|
||||
const wrapper = await mountSizedChart(gridSeries(2), {
|
||||
displayMode: 'independent',
|
||||
grid: { rowCount: 1, columnCount: 2 },
|
||||
initialXDomains: {
|
||||
'channel-0': [0, 4.999999],
|
||||
'channel-1': [10, 14.999999],
|
||||
},
|
||||
xDomainStrategy: { type: 'nice', bounds: 'end', tickCount: 10, includeExplicit: true },
|
||||
})
|
||||
|
||||
const tracks = wrapper.findAll('.waveform-chart__track')
|
||||
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
||||
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
||||
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('10000')
|
||||
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('15000')
|
||||
})
|
||||
})
|
||||
@@ -13,6 +13,7 @@ export type {
|
||||
WaveformDisplayMode,
|
||||
WaveformOverlayMode,
|
||||
WaveformInteractionMode,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
WaveformAnnotationStyle,
|
||||
|
||||
@@ -26,6 +26,17 @@ export type WaveformOverlayMode = 'single-axis' | 'multi-axis'
|
||||
/** 标注工具模式 */
|
||||
export type WaveformInteractionMode = 'zoom' | 'annotation'
|
||||
|
||||
/** Controls how the initial X viewport is derived when no explicit domain is configured. */
|
||||
export interface WaveformXDomainStrategy {
|
||||
type: 'data' | 'nice'
|
||||
/** Selects which bounds are expanded when type is `nice`. Defaults to `both`. */
|
||||
bounds?: 'both' | 'end'
|
||||
/** Stable tick count used to calculate nice bounds. Defaults to 10. */
|
||||
tickCount?: number
|
||||
/** Applies the strategy to explicit initial domains. Defaults to false. */
|
||||
includeExplicit?: boolean
|
||||
}
|
||||
|
||||
/** Describes the X-axis viewport after a zoom gesture completes. */
|
||||
export interface WaveformZoomEndPayload {
|
||||
start: number
|
||||
|
||||
@@ -8,6 +8,7 @@ export type {
|
||||
WaveformDisplayMode,
|
||||
WaveformOverlayMode,
|
||||
WaveformInteractionMode,
|
||||
WaveformXDomainStrategy,
|
||||
WaveformZoomEndPayload,
|
||||
WaveformZoomResetPayload,
|
||||
WaveformAnnotationStyle,
|
||||
|
||||
Reference in New Issue
Block a user