waveform-analysis 0.1.62 → 0.1.64
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 +9 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +953 -946
- package/dist/style.css +1 -1
- package/dist/types/types/chart.d.ts +2 -1
- package/package.json +1 -1
- package/src/components/WaveformChart.vue +1 -1
- package/src/components/core/xDomain.ts +26 -2
- package/src/components/rendering/WaveformLegend.vue +1 -1
- package/src/components/rendering/WaveformSeriesLayer.vue +1 -1
- package/src/demo/DemoChartHost.vue +1 -0
- package/src/types/chart.ts +2 -1
- package/src/App.test.ts +0 -400
- package/src/components/annotation/components.test.ts +0 -372
- package/src/components/annotation/markup.test.ts +0 -371
- package/src/components/annotation/serialization.test.ts +0 -114
- package/src/components/core/constants.test.ts +0 -29
- package/src/components/core/fixedYDomainLayout.test.ts +0 -204
- package/src/components/core/grid.test.ts +0 -197
- package/src/components/core/latestTaskScheduler.test.ts +0 -51
- package/src/components/core/layout.test.ts +0 -373
- package/src/components/core/title.test.ts +0 -76
- package/src/components/core/useWaveformData.test.ts +0 -95
- package/src/components/core/useWaveformRenderSampling.test.ts +0 -17
- package/src/components/core/xDomain.test.ts +0 -28
- package/src/components/core/yAxisNice.test.ts +0 -174
- package/src/components/core/yAxisSlotLayout.test.ts +0 -165
- package/src/components/core/yDomain.test.ts +0 -56
- package/src/components/interaction/WaveformTooltip.test.ts +0 -276
- package/src/components/interaction/viewportInteractionState.test.ts +0 -101
- package/src/components/utils/useAnimationFrameThrottle.test.ts +0 -53
- package/src/components/waveformChartCases/annotationEditingAndReprojection.test.ts +0 -257
- package/src/components/waveformChartCases/compactAndSharedHover.test.ts +0 -358
- package/src/components/waveformChartCases/dataAndHoverPerformance.test.ts +0 -358
- package/src/components/waveformChartCases/dataLifecycle.test.ts +0 -310
- package/src/components/waveformChartCases/frameGridAndFormatting.test.ts +0 -389
- package/src/components/waveformChartCases/gridFill.test.ts +0 -95
- package/src/components/waveformChartCases/incompleteDataHover.test.ts +0 -155
- package/src/components/waveformChartCases/interactionAndAnnotationCreation.test.ts +0 -328
- package/src/components/waveformChartCases/layoutAndDomains.test.ts +0 -371
- package/src/components/waveformChartCases/legendVisibility.test.ts +0 -350
- package/src/components/waveformChartCases/multiAxisAndPagination.test.ts +0 -400
- package/src/components/waveformChartCases/multiAxisLabelAlignment.test.ts +0 -61
- package/src/components/waveformChartCases/presentationAndAxes.test.ts +0 -345
- package/src/components/waveformChartCases/presentationMode.test.ts +0 -327
- package/src/components/waveformChartCases/renderingStyles.test.ts +0 -283
- package/src/components/waveformChartCases/sizingAndTitles.test.ts +0 -370
- package/src/components/waveformChartCases/trackOrder.test.ts +0 -323
- package/src/components/waveformChartCases/viewportBoxAndPan.test.ts +0 -365
- package/src/components/waveformChartCases/viewportConstraintsAndReset.test.ts +0 -311
- package/src/components/waveformChartCases/viewportLifecycle.test.ts +0 -132
- package/src/components/waveformChartCases/viewportReset.test.ts +0 -251
- package/src/components/waveformChartCases/wheelZoomOut.test.ts +0 -114
- package/src/components/waveformChartCases/workerSamplingIntegration.test.ts +0 -117
- package/src/components/waveformChartCases/xDomainStrategy.test.ts +0 -168
- package/src/components/waveformChartCases/yAxisLayout.test.ts +0 -103
- package/src/components/waveformChartCases/zoomIntentAndDataRebind.test.ts +0 -213
- package/src/components/waveformChartCases/zoomPointConstraints.test.ts +0 -308
- package/src/components/waveformLegendGeometry.test.ts +0 -21
- package/src/components/waveformNormalization.test.ts +0 -170
- package/src/core/data.test.ts +0 -241
- package/src/core/rendering.test.ts +0 -267
- package/src/core/renderingStrategies.test.ts +0 -90
- package/src/core/samplingReference.test.ts +0 -124
- package/src/core/wasmSampling.test.ts +0 -205
- package/src/core/workerSampling/multiresolution.test.ts +0 -69
- package/src/core/workerSampling/protocol.test.ts +0 -34
- package/src/core/workerSampling/repository.test.ts +0 -400
- package/src/core/workerSampling/repositoryCache.test.ts +0 -163
- package/src/core/workerSampling/repositorySampling.test.ts +0 -106
- package/src/core/workerSampling/repositoryTypedDataset.test.ts +0 -89
- package/src/core/workerSampling/repositoryWasmDataset.test.ts +0 -70
- package/src/data/simulatedWaveforms.test.ts +0 -60
- package/src/demo/plotMarginControls.test.ts +0 -29
- package/src/demo/xAxisLabelControls.test.ts +0 -86
- package/src/test/setup.ts +0 -82
- package/src/test/waveformChart.ts +0 -75
- package/src/utils/domain.test.ts +0 -28
- package/src/utils/formatters.test.ts +0 -131
- package/src/utils/sampling.test.ts +0 -226
- package/src/views/FixedYDomainDemo.test.ts +0 -44
- package/src/views/WasmSamplingDemo.test.ts +0 -13
- package/src/views/wasmSamplingDemoSampling.test.ts +0 -27
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { flushPromises } from '@vue/test-utils'
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { flushAnimationFrames } from '../../test/setup'
|
|
5
|
-
import { mountSizedChart } from '../../test/waveformChart'
|
|
6
|
-
|
|
7
|
-
describe('WaveformChart wheel zoom out', () => {
|
|
8
|
-
it('restores an independent initial domain after replacing data with a narrow window', async () => {
|
|
9
|
-
const createData = (start: number, end: number) => ({
|
|
10
|
-
kind: 'series' as const,
|
|
11
|
-
series: [
|
|
12
|
-
{
|
|
13
|
-
id: 'channel-a',
|
|
14
|
-
name: '通道 A',
|
|
15
|
-
data: {
|
|
16
|
-
kind: 'points' as const,
|
|
17
|
-
points: [
|
|
18
|
-
{ x: start, y: 0 },
|
|
19
|
-
{ x: end, y: 1 },
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
})
|
|
25
|
-
const wrapper = await mountSizedChart(createData(-5, 5), {
|
|
26
|
-
displayMode: 'independent',
|
|
27
|
-
initialXDomain: [-5, 5],
|
|
28
|
-
})
|
|
29
|
-
const overlay = wrapper.get('.waveform-chart__overlay--independent')
|
|
30
|
-
const overlayWidth = Number(overlay.attributes('width'))
|
|
31
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
32
|
-
value: () => ({ left: 0, top: 0, width: overlayWidth, height: 290 }),
|
|
33
|
-
})
|
|
34
|
-
const dispatchWheel = async (deltaY: number) => {
|
|
35
|
-
overlay.element.dispatchEvent(
|
|
36
|
-
new WheelEvent('wheel', {
|
|
37
|
-
deltaY,
|
|
38
|
-
clientX: overlayWidth / 2,
|
|
39
|
-
clientY: 145,
|
|
40
|
-
bubbles: true,
|
|
41
|
-
cancelable: true,
|
|
42
|
-
}),
|
|
43
|
-
)
|
|
44
|
-
flushAnimationFrames()
|
|
45
|
-
await flushPromises()
|
|
46
|
-
}
|
|
47
|
-
const endpoints = () => ({
|
|
48
|
-
start: wrapper.get('.waveform-chart__axis-endpoint--start').text(),
|
|
49
|
-
end: wrapper.get('.waveform-chart__axis-endpoint--end').text(),
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
expect(endpoints()).toEqual({ start: '-5000', end: '5000' })
|
|
53
|
-
await dispatchWheel(-4000)
|
|
54
|
-
expect(endpoints()).not.toEqual({ start: '-5000', end: '5000' })
|
|
55
|
-
|
|
56
|
-
await wrapper.setProps({ data: createData(-0.125, 0.125) })
|
|
57
|
-
await flushPromises()
|
|
58
|
-
await dispatchWheel(4000)
|
|
59
|
-
|
|
60
|
-
expect(endpoints()).toEqual({ start: '-5000', end: '5000' })
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('emits one zoom-end payload after zooming a shared viewport out', async () => {
|
|
64
|
-
vi.useFakeTimers()
|
|
65
|
-
try {
|
|
66
|
-
const wrapper = await mountSizedChart({
|
|
67
|
-
kind: 'points',
|
|
68
|
-
points: [
|
|
69
|
-
{ x: 0, y: 0 },
|
|
70
|
-
{ x: 2, y: 1 },
|
|
71
|
-
],
|
|
72
|
-
})
|
|
73
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
74
|
-
const overlayWidth = Number(overlay.attributes('width'))
|
|
75
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
76
|
-
value: () => ({ left: 0, top: 0, width: overlayWidth, height: 290 }),
|
|
77
|
-
})
|
|
78
|
-
const dispatchWheel = (deltaY: number) =>
|
|
79
|
-
overlay.element.dispatchEvent(
|
|
80
|
-
new WheelEvent('wheel', {
|
|
81
|
-
deltaY,
|
|
82
|
-
clientX: overlayWidth / 2,
|
|
83
|
-
clientY: 145,
|
|
84
|
-
bubbles: true,
|
|
85
|
-
cancelable: true,
|
|
86
|
-
}),
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
dispatchWheel(-4000)
|
|
90
|
-
flushAnimationFrames()
|
|
91
|
-
await vi.advanceTimersByTimeAsync(200)
|
|
92
|
-
await flushPromises()
|
|
93
|
-
const zoomedDomain = wrapper.emitted('zoom-change')?.at(-1)?.[0] as [number, number]
|
|
94
|
-
const zoomedSpan = zoomedDomain[1] - zoomedDomain[0]
|
|
95
|
-
|
|
96
|
-
dispatchWheel(1000)
|
|
97
|
-
flushAnimationFrames()
|
|
98
|
-
expect(wrapper.emitted('zoom-end')).toHaveLength(1)
|
|
99
|
-
await vi.advanceTimersByTimeAsync(200)
|
|
100
|
-
await flushPromises()
|
|
101
|
-
|
|
102
|
-
const zoomedOutPayload = wrapper.emitted('zoom-end')?.at(-1)?.[0] as {
|
|
103
|
-
start: number
|
|
104
|
-
end: number
|
|
105
|
-
gesture: string
|
|
106
|
-
}
|
|
107
|
-
expect(wrapper.emitted('zoom-end')).toHaveLength(2)
|
|
108
|
-
expect(zoomedOutPayload.end - zoomedOutPayload.start).toBeGreaterThan(zoomedSpan)
|
|
109
|
-
expect(zoomedOutPayload.gesture).toBe('wheel')
|
|
110
|
-
} finally {
|
|
111
|
-
vi.useRealTimers()
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
})
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { flushPromises } from '@vue/test-utils'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { flushAnimationFrames } from '../../test/setup'
|
|
5
|
-
import { mountSizedChart } from '../../test/waveformChart'
|
|
6
|
-
|
|
7
|
-
function densePoints(count: number) {
|
|
8
|
-
return Array.from({ length: count }, (_, index) => ({
|
|
9
|
-
x: index,
|
|
10
|
-
y: index === count - 1 ? 100 : Math.sin(index / 10),
|
|
11
|
-
}))
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function samplingEvents(count: number, rendering = {}) {
|
|
15
|
-
const wrapper = await mountSizedChart(
|
|
16
|
-
{ kind: 'points', points: densePoints(count) },
|
|
17
|
-
{ rendering, grid: { rowCount: 1, columnCount: 1 } },
|
|
18
|
-
)
|
|
19
|
-
await flushPromises()
|
|
20
|
-
await new Promise((resolve) => setTimeout(resolve, 120))
|
|
21
|
-
return wrapper
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async function compactSamplingEvents(count: number, rendering = {}) {
|
|
25
|
-
const wrapper = await mountSizedChart(
|
|
26
|
-
{
|
|
27
|
-
kind: 'typed-points',
|
|
28
|
-
x: Float64Array.from({ length: count }, (_, index) => index),
|
|
29
|
-
y: Float32Array.from({ length: count }, (_, index) =>
|
|
30
|
-
index === count - 1 ? 100 : Math.sin(index / 10),
|
|
31
|
-
),
|
|
32
|
-
},
|
|
33
|
-
{ rendering, grid: { rowCount: 1, columnCount: 1 } },
|
|
34
|
-
)
|
|
35
|
-
await flushPromises()
|
|
36
|
-
await new Promise((resolve) => setTimeout(resolve, 120))
|
|
37
|
-
return wrapper
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
describe('WaveformChart worker sampling integration', () => {
|
|
41
|
-
it('uses raw source points at the auto threshold and JavaScript fallback above it', async () => {
|
|
42
|
-
const threshold = await samplingEvents(1_000)
|
|
43
|
-
const sampled = await samplingEvents(1_001)
|
|
44
|
-
|
|
45
|
-
expect(threshold.emitted('sampling-complete')?.at(-1)?.[0]).toMatchObject({
|
|
46
|
-
mode: 'auto',
|
|
47
|
-
backend: 'raw',
|
|
48
|
-
visiblePointCount: 1_000,
|
|
49
|
-
renderedPointCount: 1_000,
|
|
50
|
-
})
|
|
51
|
-
expect(sampled.emitted('sampling-complete')?.at(-1)?.[0]).toMatchObject({
|
|
52
|
-
mode: 'auto',
|
|
53
|
-
backend: 'javascript',
|
|
54
|
-
visiblePointCount: 1_001,
|
|
55
|
-
})
|
|
56
|
-
const path = sampled.get('.waveform-chart__line').attributes('d') ?? ''
|
|
57
|
-
expect(path.match(/[ML]/g)?.length).toBeLessThan(4_000)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('bypasses worker sampling in raw mode and reports a forced-WASM failure without a fallback', async () => {
|
|
61
|
-
const raw = await samplingEvents(1_001, { sampling: { mode: 'raw' } })
|
|
62
|
-
const wasm = await samplingEvents(1_001, {
|
|
63
|
-
sampling: { mode: 'wasm', wasmFailureFallback: 'error' },
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
expect(raw.emitted('sampling-complete')?.at(-1)?.[0]).toMatchObject({
|
|
67
|
-
mode: 'raw',
|
|
68
|
-
backend: 'raw',
|
|
69
|
-
renderedPointCount: 1_001,
|
|
70
|
-
})
|
|
71
|
-
expect(raw.emitted('sampling-error')).toBeUndefined()
|
|
72
|
-
expect(wasm.emitted('sampling-complete')?.at(-1)?.[0]).toMatchObject({
|
|
73
|
-
mode: 'wasm',
|
|
74
|
-
backend: 'unavailable',
|
|
75
|
-
})
|
|
76
|
-
expect(wasm.emitted('sampling-error')?.at(-1)?.[0]).toMatchObject({
|
|
77
|
-
mode: 'wasm',
|
|
78
|
-
fallback: 'none',
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('keeps hover bound to complete source data after sampled SVG geometry is applied', async () => {
|
|
83
|
-
const wrapper = await samplingEvents(1_001)
|
|
84
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
85
|
-
const width = Number(overlay.attributes('width'))
|
|
86
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
87
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
88
|
-
})
|
|
89
|
-
overlay.element.dispatchEvent(
|
|
90
|
-
new MouseEvent('pointermove', { clientX: width, clientY: 120, bubbles: true }),
|
|
91
|
-
)
|
|
92
|
-
flushAnimationFrames()
|
|
93
|
-
await flushPromises()
|
|
94
|
-
|
|
95
|
-
expect(wrapper.emitted('point-hover')?.at(-1)).toEqual([{ x: 1_000, y: 100 }])
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('samples dense typed coordinates while retaining the full compact source for hover', async () => {
|
|
99
|
-
const wrapper = await compactSamplingEvents(1_001)
|
|
100
|
-
expect(wrapper.emitted('sampling-complete')?.at(-1)?.[0]).toMatchObject({
|
|
101
|
-
backend: 'javascript',
|
|
102
|
-
sourcePointCount: 1_001,
|
|
103
|
-
visiblePointCount: 1_001,
|
|
104
|
-
})
|
|
105
|
-
const overlay = wrapper.get('.waveform-chart__overlay')
|
|
106
|
-
const width = Number(overlay.attributes('width'))
|
|
107
|
-
Object.defineProperty(overlay.element, 'getBoundingClientRect', {
|
|
108
|
-
value: () => ({ left: 0, top: 0, width, height: 290 }),
|
|
109
|
-
})
|
|
110
|
-
overlay.element.dispatchEvent(
|
|
111
|
-
new MouseEvent('pointermove', { clientX: width, clientY: 120, bubbles: true }),
|
|
112
|
-
)
|
|
113
|
-
flushAnimationFrames()
|
|
114
|
-
await flushPromises()
|
|
115
|
-
expect(wrapper.emitted('point-hover')?.at(-1)).toEqual([{ x: 1_000, y: 100 }])
|
|
116
|
-
})
|
|
117
|
-
})
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { gridSeries, mountSizedChart } from '../../test/waveformChart'
|
|
4
|
-
|
|
5
|
-
describe('WaveformChart x domain strategy', () => {
|
|
6
|
-
it('expands automatic x domains without changing source seconds', async () => {
|
|
7
|
-
const data = {
|
|
8
|
-
kind: 'points' as const,
|
|
9
|
-
points: [
|
|
10
|
-
{ x: 0, y: 0 },
|
|
11
|
-
{ x: 4.999999, y: 1 },
|
|
12
|
-
],
|
|
13
|
-
}
|
|
14
|
-
const wrapper = await mountSizedChart(data, {
|
|
15
|
-
timeUnit: 'ms',
|
|
16
|
-
xDomainStrategy: { type: 'nice', bounds: 'end' },
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
20
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
|
21
|
-
expect(data.points[1]?.x).toBe(4.999999)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('keeps explicit initial x domains exact by default', async () => {
|
|
25
|
-
const wrapper = await mountSizedChart(
|
|
26
|
-
{
|
|
27
|
-
kind: 'points',
|
|
28
|
-
points: [
|
|
29
|
-
{ x: 123, y: 0 },
|
|
30
|
-
{ x: 456, y: 1 },
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
timeUnit: 's',
|
|
35
|
-
initialXDomain: [120, 460],
|
|
36
|
-
xDomainStrategy: { type: 'nice' },
|
|
37
|
-
},
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('120')
|
|
41
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('460')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('keeps explicit per-track initial x domains exact by default', async () => {
|
|
45
|
-
const wrapper = await mountSizedChart(gridSeries(1), {
|
|
46
|
-
displayMode: 'independent',
|
|
47
|
-
initialXDomains: { 'channel-0': [0, 4.999999] },
|
|
48
|
-
xDomainStrategy: { type: 'nice', bounds: 'end' },
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
52
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('4999.999')
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('includes an explicit shared initial x domain when requested', async () => {
|
|
56
|
-
const wrapper = await mountSizedChart(
|
|
57
|
-
{
|
|
58
|
-
kind: 'points',
|
|
59
|
-
points: [
|
|
60
|
-
{ x: 0, y: 0 },
|
|
61
|
-
{ x: 4.999999, y: 1 },
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
initialXDomain: [0, 4.999999],
|
|
66
|
-
xDomainStrategy: {
|
|
67
|
-
type: 'nice',
|
|
68
|
-
bounds: 'end',
|
|
69
|
-
tickCount: 10,
|
|
70
|
-
includeExplicit: true,
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
76
|
-
expect(wrapper.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('includes explicit per-track initial x domains in independent mode', async () => {
|
|
80
|
-
const wrapper = await mountSizedChart(gridSeries(2), {
|
|
81
|
-
displayMode: 'independent',
|
|
82
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
83
|
-
initialXDomains: {
|
|
84
|
-
'channel-0': [0, 4.999999],
|
|
85
|
-
'channel-1': [10, 14.999999],
|
|
86
|
-
},
|
|
87
|
-
xDomainStrategy: { type: 'nice', bounds: 'end', tickCount: 10, includeExplicit: true },
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const tracks = wrapper.findAll('.waveform-chart__track')
|
|
91
|
-
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('0')
|
|
92
|
-
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('5000')
|
|
93
|
-
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('10000')
|
|
94
|
-
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('15000')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('keeps an explicit viewport wider than the data and leaves uncovered time blank', async () => {
|
|
98
|
-
const wrapper = await mountSizedChart(
|
|
99
|
-
{
|
|
100
|
-
kind: 'points',
|
|
101
|
-
points: [
|
|
102
|
-
{ x: 0, y: 0 },
|
|
103
|
-
{ x: 10, y: 1 },
|
|
104
|
-
],
|
|
105
|
-
},
|
|
106
|
-
{ timeUnit: 's', initialXDomain: [-5, 20] },
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
const track = wrapper.get('.waveform-chart__track')
|
|
110
|
-
const width = Number(track.attributes('data-track-width'))
|
|
111
|
-
const path = track.get('.waveform-chart__line').attributes('d') ?? ''
|
|
112
|
-
const xCoordinates = Array.from(path.matchAll(/(?:M|L)([\d.-]+)/g)).map((match) =>
|
|
113
|
-
Number(match[1]),
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
expect(track.get('.waveform-chart__axis-endpoint--start').text()).toBe('-5')
|
|
117
|
-
expect(track.get('.waveform-chart__axis-endpoint--end').text()).toBe('20')
|
|
118
|
-
expect(xCoordinates.length).toBeGreaterThan(0)
|
|
119
|
-
expect(Math.min(...xCoordinates)).toBeGreaterThanOrEqual(0)
|
|
120
|
-
expect(Math.max(...xCoordinates)).toBeLessThanOrEqual(width)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('applies independent explicit viewports per track, including empty time regions', async () => {
|
|
124
|
-
const wrapper = await mountSizedChart(
|
|
125
|
-
{
|
|
126
|
-
kind: 'series',
|
|
127
|
-
series: [
|
|
128
|
-
{
|
|
129
|
-
id: 'first',
|
|
130
|
-
name: '第一轨',
|
|
131
|
-
data: {
|
|
132
|
-
kind: 'points',
|
|
133
|
-
points: [
|
|
134
|
-
{ x: 0, y: 0 },
|
|
135
|
-
{ x: 10, y: 1 },
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
id: 'second',
|
|
141
|
-
name: '第二轨',
|
|
142
|
-
data: {
|
|
143
|
-
kind: 'points',
|
|
144
|
-
points: [
|
|
145
|
-
{ x: 100, y: 0 },
|
|
146
|
-
{ x: 110, y: 1 },
|
|
147
|
-
],
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
],
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
displayMode: 'independent',
|
|
154
|
-
grid: { rowCount: 1, columnCount: 2 },
|
|
155
|
-
timeUnit: 's',
|
|
156
|
-
initialXDomains: { first: [-5, 20], second: [95, 120] },
|
|
157
|
-
},
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
const tracks = wrapper.findAll('.waveform-chart__track')
|
|
161
|
-
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('-5')
|
|
162
|
-
expect(tracks[0]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('20')
|
|
163
|
-
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--start').text()).toBe('95')
|
|
164
|
-
expect(tracks[1]?.get('.waveform-chart__axis-endpoint--end').text()).toBe('120')
|
|
165
|
-
expect(tracks[0]?.find('.waveform-chart__line').exists()).toBe(true)
|
|
166
|
-
expect(tracks[1]?.find('.waveform-chart__line').exists()).toBe(true)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { flushPromises } from '@vue/test-utils'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { resizeObservers } from '../../test/setup'
|
|
5
|
-
|
|
6
|
-
import { mountSizedChart } from '../../test/waveformChart'
|
|
7
|
-
|
|
8
|
-
describe('WaveformChart Y-axis layout', () => {
|
|
9
|
-
it('applies the configured Y-axis split number', async () => {
|
|
10
|
-
const wrapper = await mountSizedChart(
|
|
11
|
-
{
|
|
12
|
-
kind: 'points',
|
|
13
|
-
points: [
|
|
14
|
-
{ x: 0, y: 3 },
|
|
15
|
-
{ x: 1, y: 97 },
|
|
16
|
-
],
|
|
17
|
-
},
|
|
18
|
-
{ axes: { y: { splitNumber: 5 } } },
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
expect(
|
|
22
|
-
wrapper
|
|
23
|
-
.get('.waveform-chart__axis--y')
|
|
24
|
-
.findAll('.tick text')
|
|
25
|
-
.map((tick) => tick.text()),
|
|
26
|
-
).toEqual(['0', '25', '50', '75', '100'])
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('reserves the rendered endpoint label width across tracks, pages, and resizes', async () => {
|
|
30
|
-
const wrapper = await mountSizedChart(
|
|
31
|
-
{
|
|
32
|
-
kind: 'series',
|
|
33
|
-
series: ['WE_2M', 'IP_VV_2M', 'SX2_7_07', 'BT1_2M'].map((name, index) => ({
|
|
34
|
-
id: name,
|
|
35
|
-
name,
|
|
36
|
-
unit: 'V',
|
|
37
|
-
data: {
|
|
38
|
-
kind: 'points' as const,
|
|
39
|
-
points: [
|
|
40
|
-
{ x: 0, y: -0.7434 - index },
|
|
41
|
-
{ x: 1, y: -0.3434 - index },
|
|
42
|
-
],
|
|
43
|
-
},
|
|
44
|
-
})),
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
axes: { y: { lineVisible: false, nice: false } },
|
|
48
|
-
grid: { rowCount: 1, columnCount: 1 },
|
|
49
|
-
},
|
|
50
|
-
)
|
|
51
|
-
const firstTrack = wrapper.get('.waveform-chart__track')
|
|
52
|
-
|
|
53
|
-
expect(wrapper.attributes('data-chart-left-margin')).toBe('100')
|
|
54
|
-
expect(firstTrack.attributes('data-y-axis-label-x')).toBe('-90')
|
|
55
|
-
expect(firstTrack.findAll('.waveform-chart__axis--y .tick text').at(-1)?.text()).toBe(
|
|
56
|
-
'(V) -0.3434',
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
resizeObservers.at(-1)?.resize(520, 280)
|
|
60
|
-
await flushPromises()
|
|
61
|
-
expect(wrapper.attributes('data-chart-left-margin')).toBe('100')
|
|
62
|
-
expect(wrapper.get('.waveform-chart__track').attributes('data-y-axis-label-x')).toBe('-90')
|
|
63
|
-
|
|
64
|
-
await wrapper.get('.ant-pagination-next button').trigger('click')
|
|
65
|
-
expect(wrapper.attributes('data-chart-left-margin')).toBe('100')
|
|
66
|
-
expect(wrapper.get('.waveform-chart__track').attributes('data-y-axis-label-x')).toBe('-90')
|
|
67
|
-
expect(wrapper.get('.waveform-chart__axis--y').findAll('.tick text').at(-1)?.text()).toBe(
|
|
68
|
-
'(V) -1.3434',
|
|
69
|
-
)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('measures the compact-row unit label after omitting the top endpoint', async () => {
|
|
73
|
-
const wrapper = await mountSizedChart(
|
|
74
|
-
{
|
|
75
|
-
kind: 'series',
|
|
76
|
-
series: ['first', 'second'].map((id) => ({
|
|
77
|
-
id,
|
|
78
|
-
name: id,
|
|
79
|
-
unit: 'V',
|
|
80
|
-
data: {
|
|
81
|
-
kind: 'points' as const,
|
|
82
|
-
points: [
|
|
83
|
-
{ x: 0, y: 0.12345 },
|
|
84
|
-
{ x: 1, y: 100 },
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
})),
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
displayMode: 'compact',
|
|
91
|
-
axes: { y: { nice: false } },
|
|
92
|
-
grid: { rowCount: 2, columnCount: 1 },
|
|
93
|
-
},
|
|
94
|
-
)
|
|
95
|
-
const tracks = wrapper.findAll('.waveform-chart__track')
|
|
96
|
-
|
|
97
|
-
expect(wrapper.attributes('data-chart-left-margin')).toBe('93')
|
|
98
|
-
expect(tracks[1]?.attributes('data-y-axis-label-x')).toBe('-83')
|
|
99
|
-
expect(tracks[1]?.findAll('.waveform-chart__axis--y .tick text').at(-1)?.text()).toBe(
|
|
100
|
-
'(V) 75.031',
|
|
101
|
-
)
|
|
102
|
-
})
|
|
103
|
-
})
|