waveform-analysis 0.1.76 → 0.1.77
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 +12 -26
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/dist/types/components/animation/context.d.ts +1 -0
- package/dist/types/components/animation/paginationPresentation.d.ts +7 -7
- package/dist/types/components/animation/useWaveformAnimations.d.ts +1 -18
- package/dist/types/components/core/useWaveformChartController.d.ts +1 -18
- package/dist/types/components/rendering/WaveformSeriesLayer.vue.d.ts +0 -1
- package/dist/types/components/rendering/WaveformTrack.vue.d.ts +0 -1
- package/package.json +1 -1
- package/src/components/WaveformChartView.vue +0 -2
- package/src/components/animation/config.ts +1 -1
- package/src/components/animation/context.ts +9 -1
- package/src/components/animation/paginationPresentation.ts +55 -64
- package/src/components/animation/useWaveformAnimations.ts +36 -13
- package/src/components/core/useWaveformChartController.ts +0 -1
- package/src/components/rendering/WaveformSeriesLayer.vue +1 -2
- package/src/components/rendering/WaveformTrack.vue +1 -6
- package/src/views/AnimationDemo.vue +14 -5
|
@@ -13,7 +13,12 @@ import { chartExportOptions } from '../controls/chartExportOptions'
|
|
|
13
13
|
import { layoutAnnotations } from '../annotation/annotationLayout'
|
|
14
14
|
import { useWaveformInstanceId } from '@/utils/waveformId'
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
animationGridShape,
|
|
18
|
+
animationLayoutSignature,
|
|
19
|
+
wrapAnimationCommands,
|
|
20
|
+
type AnimationContext,
|
|
21
|
+
} from './context'
|
|
17
22
|
import { createPaginationPresentation } from './paginationPresentation'
|
|
18
23
|
|
|
19
24
|
export function useWaveformAnimations(context: AnimationContext) {
|
|
@@ -26,6 +31,8 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
26
31
|
const seen = new Set<string>()
|
|
27
32
|
const prefix = useWaveformInstanceId('waveform-animation')
|
|
28
33
|
let clipSequence = 0
|
|
34
|
+
let presentationGeneration = 0
|
|
35
|
+
let previousGrid = animationGridShape(context)
|
|
29
36
|
let previousAnnotations = props.annotations
|
|
30
37
|
let previousData = props.data
|
|
31
38
|
let previousLayout = ''
|
|
@@ -63,9 +70,12 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
63
70
|
states.has(track.id) ? projectTrack(states.get(track.id)!) : track,
|
|
64
71
|
)
|
|
65
72
|
})
|
|
66
|
-
const pagination = createPaginationPresentation(context, controller, config, effective, () =>
|
|
67
|
-
commit(true)
|
|
68
|
-
|
|
73
|
+
const pagination = createPaginationPresentation(context, controller, config, effective, () => {
|
|
74
|
+
commit(true)
|
|
75
|
+
for (const track of tracks.value) for (const series of track.seriesList) seen.delete(series.id)
|
|
76
|
+
skipSignature = undefined
|
|
77
|
+
annotations.clear()
|
|
78
|
+
})
|
|
69
79
|
const projectedAnnotations = computed(() => {
|
|
70
80
|
const anchors = new Map([...states.values()].flatMap((state) => [...state.anchors]))
|
|
71
81
|
const values = visibleAnnotations().flatMap((annotation) => {
|
|
@@ -100,12 +110,10 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
100
110
|
[...state.series].map(([id, series]) => [id, series.opacity] as const),
|
|
101
111
|
),
|
|
102
112
|
)
|
|
103
|
-
return annotations.project(projectedAnnotations.value, opacities)
|
|
104
|
-
...annotation,
|
|
105
|
-
seriesOpacity: (annotation.seriesOpacity ?? 1) * pagination.opacity.value,
|
|
106
|
-
}))
|
|
113
|
+
return annotations.project(projectedAnnotations.value, opacities)
|
|
107
114
|
})
|
|
108
115
|
function commit(preservePagination = false) {
|
|
116
|
+
presentationGeneration++
|
|
109
117
|
if (!preservePagination) pagination.reset()
|
|
110
118
|
const previous = new Map(states)
|
|
111
119
|
states.clear()
|
|
@@ -130,6 +138,8 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
130
138
|
if (disposed) return
|
|
131
139
|
const nextConfig = config.value
|
|
132
140
|
const dataChanged = props.data !== previousData
|
|
141
|
+
// The post-flush grid watcher waits for lifecycle page resets before requesting replay.
|
|
142
|
+
if (!dataChanged && seen.size && animationGridShape(context) !== previousGrid) return
|
|
133
143
|
if (dataChanged) {
|
|
134
144
|
pendingFrom = new Map(states)
|
|
135
145
|
previousData = props.data
|
|
@@ -162,8 +172,9 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
162
172
|
previousTracks = tracks.value
|
|
163
173
|
previousSamplingState = sampling.state.value
|
|
164
174
|
controller.setEnabled(effective.value)
|
|
165
|
-
|
|
166
|
-
if (
|
|
175
|
+
const replay = pagination.reconcile(dataChanged)
|
|
176
|
+
if (replay === 'static') return
|
|
177
|
+
if (!effective.value || (layoutChanged && !replay)) {
|
|
167
178
|
controller.finishAll()
|
|
168
179
|
commit()
|
|
169
180
|
return
|
|
@@ -224,6 +235,7 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
224
235
|
if (
|
|
225
236
|
!seen.has(id) &&
|
|
226
237
|
nextConfig.animation.enabled &&
|
|
238
|
+
nextConfig.animation.duration > 0 &&
|
|
227
239
|
skipSignature !== sampling.requestSignature.value
|
|
228
240
|
) {
|
|
229
241
|
const state = states.get(track.id)!
|
|
@@ -255,8 +267,10 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
255
267
|
invalidate()
|
|
256
268
|
},
|
|
257
269
|
}
|
|
270
|
+
const generation = presentationGeneration
|
|
258
271
|
controller.animateSeriesEnter(id, binding, track.width, {
|
|
259
272
|
...nextConfig.animation,
|
|
273
|
+
duration: pagination.enterDuration(),
|
|
260
274
|
delay:
|
|
261
275
|
nextConfig.animation.delay + visibleIds.indexOf(id) * nextConfig.animation.staggerDelay,
|
|
262
276
|
onComplete: () => {
|
|
@@ -264,7 +278,7 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
264
278
|
entering.delete(id)
|
|
265
279
|
invalidate()
|
|
266
280
|
queueMicrotask(() => {
|
|
267
|
-
if (!disposed) annotations.release(id)
|
|
281
|
+
if (!disposed && presentationGeneration === generation) annotations.release(id)
|
|
268
282
|
})
|
|
269
283
|
nextConfig.animation.onComplete?.()
|
|
270
284
|
},
|
|
@@ -311,6 +325,17 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
311
325
|
reconcile,
|
|
312
326
|
{ immediate: true },
|
|
313
327
|
)
|
|
328
|
+
watch(
|
|
329
|
+
[() => animationGridShape(context), () => props.data],
|
|
330
|
+
([shape, data], [previousShape, previousData]) => {
|
|
331
|
+
previousGrid = shape
|
|
332
|
+
if (disposed || shape === previousShape || data !== previousData || !seen.size) return
|
|
333
|
+
// Lifecycle page resets have now selected the final grid and page.
|
|
334
|
+
pagination.requestLayout()
|
|
335
|
+
reconcile()
|
|
336
|
+
},
|
|
337
|
+
{ flush: 'post' },
|
|
338
|
+
)
|
|
314
339
|
watch(
|
|
315
340
|
() => props.annotationsVisible,
|
|
316
341
|
(visible) => {
|
|
@@ -343,7 +368,6 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
343
368
|
controller.finishWhere(
|
|
344
369
|
(key) => key.scope === 'update' || key.scope === 'domain',
|
|
345
370
|
() => {
|
|
346
|
-
pagination.reset()
|
|
347
371
|
for (const track of tracks.value) {
|
|
348
372
|
const old = states.get(track.id),
|
|
349
373
|
next = staticTrack(track, visibleAnnotations(), old, true)
|
|
@@ -405,7 +429,6 @@ export function useWaveformAnimations(context: AnimationContext) {
|
|
|
405
429
|
return {
|
|
406
430
|
presentationTracks,
|
|
407
431
|
presentationAnnotations,
|
|
408
|
-
paginationOpacity: pagination.opacity,
|
|
409
432
|
stabilizeAnimations,
|
|
410
433
|
wrap: <T extends object>(commands: T) => wrapAnimationCommands(commands, stabilizeAnimations),
|
|
411
434
|
wrapPagination: pagination.wrapPagination,
|
|
@@ -422,7 +422,6 @@ export function useWaveformChartController(
|
|
|
422
422
|
...animations.wrap(commands),
|
|
423
423
|
presentationTracks: animations.presentationTracks,
|
|
424
424
|
presentationAnnotations: animations.presentationAnnotations,
|
|
425
|
-
paginationOpacity: animations.paginationOpacity,
|
|
426
425
|
stabilizeAnimations: animations.stabilizeAnimations,
|
|
427
426
|
...imageExport,
|
|
428
427
|
margin,
|
|
@@ -7,7 +7,6 @@ import { waveformLineDasharray, waveformPointSeriesPath } from './seriesStyle'
|
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
9
|
track: TrackLayout
|
|
10
|
-
paginationOpacity?: number
|
|
11
10
|
clipPathId: string
|
|
12
11
|
}>()
|
|
13
12
|
|
|
@@ -53,7 +52,7 @@ const renderedSeriesPaths = computed<RenderedSeriesPath[]>(() =>
|
|
|
53
52
|
<g
|
|
54
53
|
v-for="seriesPath in renderedSeriesPaths"
|
|
55
54
|
:key="seriesPath.presentationKey ?? seriesPath.series.id"
|
|
56
|
-
:opacity="
|
|
55
|
+
:opacity="seriesPath.opacity ?? 1"
|
|
57
56
|
:clip-path="seriesPath.animationClip ? `url(#${seriesPath.animationClip.id})` : undefined"
|
|
58
57
|
class="waveform-track__series-item waveform-chart__series"
|
|
59
58
|
:data-series-id="seriesPath.series.id"
|
|
@@ -12,7 +12,6 @@ import WaveformTrackBackdrop from './WaveformTrackBackdrop.vue'
|
|
|
12
12
|
|
|
13
13
|
interface Props {
|
|
14
14
|
track: TrackLayout
|
|
15
|
-
paginationOpacity?: number
|
|
16
15
|
clipPathId: string
|
|
17
16
|
innerWidth: number
|
|
18
17
|
zoomable: boolean
|
|
@@ -137,11 +136,7 @@ const frameInset = computed(() =>
|
|
|
137
136
|
aria-hidden="true"
|
|
138
137
|
/>
|
|
139
138
|
|
|
140
|
-
<WaveformSeriesLayer
|
|
141
|
-
:track="track"
|
|
142
|
-
:clip-path-id="clipPathId"
|
|
143
|
-
:pagination-opacity="paginationOpacity"
|
|
144
|
-
/>
|
|
139
|
+
<WaveformSeriesLayer :track="track" :clip-path-id="clipPathId" />
|
|
145
140
|
<WaveformZeroLines
|
|
146
141
|
:track="track"
|
|
147
142
|
:clip-path-id="clipPathId"
|
|
@@ -13,6 +13,7 @@ const enter = ref(true)
|
|
|
13
13
|
const update = ref(true)
|
|
14
14
|
const annotationEnabled = ref(true)
|
|
15
15
|
const effect = ref<AnnotationAnimationType>('scale')
|
|
16
|
+
const gridShape = ref('1x1')
|
|
16
17
|
const direction = ref<LineDrawingDirection>('left-to-right')
|
|
17
18
|
let generation = 0
|
|
18
19
|
function generate(count = 500): WaveformData {
|
|
@@ -55,13 +56,13 @@ function toggleAnnotation() {
|
|
|
55
56
|
<main class="animation-demo">
|
|
56
57
|
<h1>波形动画</h1>
|
|
57
58
|
<p>
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
分别控制入场、更新和标注效果。分页与网格调整重播波形绘制,标注等待对应系列完成,
|
|
60
|
+
坐标轴立即更新。拖动、缩放与导出会提交最终画面。
|
|
60
61
|
</p>
|
|
61
62
|
<div class="animation-demo__controls">
|
|
62
63
|
<label><input v-model="enabled" type="checkbox" /> 动画</label>
|
|
63
|
-
<label><input v-model="enter" type="checkbox" />
|
|
64
|
-
<label><input v-model="update" type="checkbox" />
|
|
64
|
+
<label><input v-model="enter" type="checkbox" /> 入场 / 切页 / 网格</label>
|
|
65
|
+
<label><input v-model="update" type="checkbox" /> 更新</label>
|
|
65
66
|
<label><input v-model="annotationEnabled" type="checkbox" /> 标注</label>
|
|
66
67
|
<label
|
|
67
68
|
>入场方向
|
|
@@ -80,6 +81,14 @@ function toggleAnnotation() {
|
|
|
80
81
|
<option value="bounce">弹跳</option>
|
|
81
82
|
</select></label
|
|
82
83
|
>
|
|
84
|
+
<label
|
|
85
|
+
>网格
|
|
86
|
+
<select v-model="gridShape" aria-label="网格">
|
|
87
|
+
<option value="1x1">1×1</option>
|
|
88
|
+
<option value="1x2">1×2</option>
|
|
89
|
+
<option value="2x2">2×2</option>
|
|
90
|
+
</select>
|
|
91
|
+
</label>
|
|
83
92
|
<button @click="key++">重新入场</button>
|
|
84
93
|
<button @click="replace(true)">更新振幅</button>
|
|
85
94
|
<button @click="replace(false)">改变点数</button>
|
|
@@ -89,7 +98,7 @@ function toggleAnnotation() {
|
|
|
89
98
|
:key="key"
|
|
90
99
|
:data="data"
|
|
91
100
|
:height="360"
|
|
92
|
-
:grid="{ rowCount:
|
|
101
|
+
:grid="{ rowCount: Number(gridShape[0]), columnCount: Number(gridShape[2]) }"
|
|
93
102
|
:animation-enabled="enabled"
|
|
94
103
|
:animation="{ enabled: enter, direction }"
|
|
95
104
|
:animation-update="{ enabled: update }"
|