@zcomponent/core 1.12.0 → 1.14.0-beta
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/lib/animation/animation.d.ts +1 -1
- package/lib/animation/animation.js +65 -35
- package/lib/animation/clips/clip.d.ts +2 -1
- package/lib/animation/clips/clip.js +9 -2
- package/lib/animation/layer.js +1 -1
- package/lib/animation/layerclip.d.ts +14 -1
- package/lib/animation/layerclip.js +79 -18
- package/lib/animation/stream.d.ts +1 -0
- package/lib/animation/tracks/cliptrack.d.ts +2 -1
- package/lib/animation/tracks/cliptrack.js +5 -2
- package/lib/animation/tracks/functiontrack.d.ts +1 -1
- package/lib/animation/tracks/functiontrack.js +1 -1
- package/lib/animation/tracks/streamtrack.d.ts +2 -1
- package/lib/animation/tracks/streamtrack.js +5 -2
- package/lib/animation/tracks/track.d.ts +1 -0
- package/lib/animation/tracks/track.js +3 -0
- package/lib/inflate.js +22 -2
- package/lib/observable.d.ts +1 -1
- package/lib/observable.js +70 -42
- package/package.json +2 -2
|
@@ -51,12 +51,12 @@ export declare class Animation {
|
|
|
51
51
|
tick(): void;
|
|
52
52
|
registerEntityPath(path: string, entity: any, pathParts: (string | number)[]): void;
|
|
53
53
|
evaluateTouchedPaths(paths: string[], t?: number): void;
|
|
54
|
+
private _evaluateLayer;
|
|
54
55
|
get spotlightLayer(): Layer | undefined;
|
|
55
56
|
set spotlightLayer(l: Layer | undefined);
|
|
56
57
|
clearCachedDefault(entityID: string, prop: string): void;
|
|
57
58
|
private _emitPendingEvents;
|
|
58
59
|
private _resolvePath;
|
|
59
|
-
private _evaluatePath;
|
|
60
60
|
start(): void;
|
|
61
61
|
}
|
|
62
62
|
export interface EntityPath {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Observable } from '../observable';
|
|
2
|
-
import { clone } from '../data';
|
|
3
2
|
import { Event } from '../event';
|
|
4
3
|
/** @internal */
|
|
5
4
|
export var AnimationEvents;
|
|
@@ -109,11 +108,58 @@ export class Animation {
|
|
|
109
108
|
return;
|
|
110
109
|
t = t ?? this.timeSource?.() ?? performance.now();
|
|
111
110
|
const unique = new Set([...paths]);
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
const uniqueAsArray = unique.values();
|
|
112
|
+
const resolvedPaths = [...uniqueAsArray].map(entry => this._resolvePath(entry));
|
|
113
|
+
for (const entry of resolvedPaths) {
|
|
114
|
+
if (!entry)
|
|
115
|
+
continue;
|
|
116
|
+
let byEntity = this._defaultValues.get(entry[0]);
|
|
117
|
+
if (!byEntity) {
|
|
118
|
+
byEntity = new Map();
|
|
119
|
+
this._defaultValues.set(entry[0], byEntity);
|
|
120
|
+
}
|
|
121
|
+
let observable = byEntity.get(entry[1][0]);
|
|
122
|
+
if (!observable) {
|
|
123
|
+
let val = entry[0][entry[1][0]];
|
|
124
|
+
if (val instanceof Observable)
|
|
125
|
+
val = val.value;
|
|
126
|
+
observable = new Observable(val);
|
|
127
|
+
byEntity.set(entry[1][0], observable);
|
|
128
|
+
}
|
|
129
|
+
entry[2] = observable;
|
|
130
|
+
}
|
|
131
|
+
// Reset our working values to default
|
|
132
|
+
for (const p of resolvedPaths) {
|
|
133
|
+
if (p?.[2])
|
|
134
|
+
p[2].value = undefined;
|
|
135
|
+
}
|
|
136
|
+
if (this._spotlightLayer)
|
|
137
|
+
this._evaluateLayer(t, this._spotlightLayer, resolvedPaths);
|
|
138
|
+
else {
|
|
139
|
+
for (const layer of this._layers)
|
|
140
|
+
this._evaluateLayer(t, layer, resolvedPaths);
|
|
141
|
+
}
|
|
142
|
+
for (const entry of resolvedPaths) {
|
|
143
|
+
if (!entry?.[2])
|
|
144
|
+
continue;
|
|
145
|
+
if (entry[0][entry[1][0]] instanceof Observable)
|
|
146
|
+
entry[0][entry[1][0]].value = entry[2].value;
|
|
147
|
+
else
|
|
148
|
+
entry[0][entry[1][0]] = entry[2].value;
|
|
114
149
|
}
|
|
115
150
|
this._emitPendingEvents();
|
|
116
151
|
}
|
|
152
|
+
_evaluateLayer(t, layer, paths) {
|
|
153
|
+
for (const p of paths) {
|
|
154
|
+
if (!p?.[2])
|
|
155
|
+
continue;
|
|
156
|
+
if (!layer.influencedPaths.has(p[3]))
|
|
157
|
+
continue;
|
|
158
|
+
let val = getResolved(p[2], p[1]);
|
|
159
|
+
val = layer.computePathProperty(t, p[3], val);
|
|
160
|
+
setResolved(p[2], p[1], val);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
117
163
|
get spotlightLayer() {
|
|
118
164
|
return this._spotlightLayer;
|
|
119
165
|
}
|
|
@@ -153,38 +199,7 @@ export class Animation {
|
|
|
153
199
|
const path = this._entityPaths.get(p);
|
|
154
200
|
if (!path || path.pathParts.length === 0)
|
|
155
201
|
return;
|
|
156
|
-
|
|
157
|
-
let currentKey = path.pathParts[0];
|
|
158
|
-
if (parent[currentKey] instanceof Observable) {
|
|
159
|
-
parent = parent[currentKey];
|
|
160
|
-
currentKey = 'value';
|
|
161
|
-
}
|
|
162
|
-
for (let i = 1; i < path.pathParts.length; i++) {
|
|
163
|
-
parent = parent[currentKey];
|
|
164
|
-
currentKey = path.pathParts[i];
|
|
165
|
-
}
|
|
166
|
-
return [parent, currentKey];
|
|
167
|
-
}
|
|
168
|
-
_evaluatePath(t, p) {
|
|
169
|
-
const resolved = this._resolvePath(p);
|
|
170
|
-
if (!resolved)
|
|
171
|
-
return;
|
|
172
|
-
if (!this._defaultValues.has(p)) {
|
|
173
|
-
this._defaultValues.set(p, clone(resolved[0][resolved[1]]));
|
|
174
|
-
}
|
|
175
|
-
let val = this._defaultValues.get(p);
|
|
176
|
-
if (this._spotlightLayer) {
|
|
177
|
-
if (this._spotlightLayer.influencedPaths.has(p))
|
|
178
|
-
val = this._spotlightLayer.computePathProperty(t, p, val);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
for (const layer of this._layers) {
|
|
182
|
-
if (!layer.influencedPaths.has(p))
|
|
183
|
-
continue;
|
|
184
|
-
val = layer.computePathProperty(t, p, val);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
resolved[0][resolved[1]] = val;
|
|
202
|
+
return [path.entity, path.pathParts, undefined, p];
|
|
188
203
|
}
|
|
189
204
|
start() {
|
|
190
205
|
for (const layer of this._layers) {
|
|
@@ -195,3 +210,18 @@ export class Animation {
|
|
|
195
210
|
}
|
|
196
211
|
}
|
|
197
212
|
}
|
|
213
|
+
function getResolved(o, pathParts) {
|
|
214
|
+
let current = o.value;
|
|
215
|
+
for (let i = 1; i < pathParts.length; i++)
|
|
216
|
+
current = current[pathParts[i]];
|
|
217
|
+
return current;
|
|
218
|
+
}
|
|
219
|
+
function setResolved(o, pathParts, val) {
|
|
220
|
+
let target = o;
|
|
221
|
+
let key = 'value';
|
|
222
|
+
for (let i = 1; i < pathParts.length; i++) {
|
|
223
|
+
target = target[key];
|
|
224
|
+
key = pathParts[i];
|
|
225
|
+
}
|
|
226
|
+
target[key] = val;
|
|
227
|
+
}
|
|
@@ -33,5 +33,6 @@ export declare class Clip {
|
|
|
33
33
|
resolveClipTime(t: number, t0: number, s0: number, rate: number, t1?: number): number;
|
|
34
34
|
streamPause(isActive: boolean, active: LayerClip | null | undefined): void;
|
|
35
35
|
streamSeek(t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined): void;
|
|
36
|
-
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, parentWeight?: number): void;
|
|
36
|
+
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, stalled?: boolean, parentWeight?: number): void;
|
|
37
|
+
isStalled(): boolean;
|
|
37
38
|
}
|
|
@@ -126,9 +126,16 @@ export class Clip {
|
|
|
126
126
|
track.streamSeek(t, rate, isActive, active);
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
streamTick(clipState, t, rate, isActive, active, force = false, parentWeight) {
|
|
129
|
+
streamTick(clipState, t, rate, isActive, active, force = false, stalled = false, parentWeight) {
|
|
130
130
|
for (const track of this._streamTracks) {
|
|
131
|
-
track.streamTick(clipState, t, rate, isActive, active, force, parentWeight);
|
|
131
|
+
track.streamTick(clipState, t, rate, isActive, active, force, stalled, parentWeight);
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
|
+
isStalled() {
|
|
135
|
+
for (const track of this._tracks) {
|
|
136
|
+
if (track.isStalled())
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
134
141
|
}
|
package/lib/animation/layer.js
CHANGED
|
@@ -45,7 +45,7 @@ export class Layer {
|
|
|
45
45
|
this._queue.splice(i, 1);
|
|
46
46
|
}
|
|
47
47
|
if (entry.layerClip && entry === this._active) {
|
|
48
|
-
if (next && (entry.layerClip.state === StreamState.Ended || next.fadeTime >= entry.layerClip.getRemainingTimeEstimate())) {
|
|
48
|
+
if (next && (entry.layerClip.state.value === StreamState.Ended || next.fadeTime >= entry.layerClip.getRemainingTimeEstimate())) {
|
|
49
49
|
next.startTime = t;
|
|
50
50
|
this._active = next;
|
|
51
51
|
this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipActive, args: [this._active.layerClip] });
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { FadeParameters } from '../data';
|
|
2
|
+
import { Event } from '../event';
|
|
3
|
+
import { Observable } from '../observable';
|
|
2
4
|
import { Animation } from './animation';
|
|
3
5
|
import { AnimationState } from './animationstate';
|
|
4
6
|
import { Clip } from './clips/clip';
|
|
@@ -16,6 +18,7 @@ export declare class LayerClip implements Stream {
|
|
|
16
18
|
readonly animation: Animation;
|
|
17
19
|
private _t0;
|
|
18
20
|
private _pauseTime;
|
|
21
|
+
private _stallStartTime;
|
|
19
22
|
private _t1;
|
|
20
23
|
private _rate;
|
|
21
24
|
private _loop;
|
|
@@ -23,17 +26,26 @@ export declare class LayerClip implements Stream {
|
|
|
23
26
|
private _lastClipTime;
|
|
24
27
|
private _lastLoop;
|
|
25
28
|
private _stopped;
|
|
26
|
-
|
|
29
|
+
private _state;
|
|
30
|
+
state: Observable<StreamState, never>;
|
|
31
|
+
playing: Observable<boolean, never>;
|
|
32
|
+
stalled: Observable<boolean, never>;
|
|
33
|
+
onPlaying: Event<[LayerClip]>;
|
|
34
|
+
onPaused: Event<[LayerClip]>;
|
|
35
|
+
onEnded: Event<[LayerClip]>;
|
|
36
|
+
onLoop: Event<[LayerClip]>;
|
|
27
37
|
constructor(layer: Layer, clip: Clip, scriptName?: string | undefined, id?: string | undefined);
|
|
28
38
|
private _clipDirty;
|
|
29
39
|
tick(touchedPaths: string[], force?: boolean): void;
|
|
30
40
|
computePathProperty(p: string, valueBefore: any): any;
|
|
31
41
|
getRemainingTimeEstimate(): number;
|
|
32
42
|
private _getTime;
|
|
43
|
+
private _stateUpdate;
|
|
33
44
|
queue(opts?: LayerClipPlayOptions): void;
|
|
34
45
|
length(): number;
|
|
35
46
|
play(opts?: LayerClipPlayOptions): void;
|
|
36
47
|
pause(): void;
|
|
48
|
+
private _cancelStall;
|
|
37
49
|
seek(ct: number, opts?: LayerClipSeekOptions): void;
|
|
38
50
|
/** @internal */
|
|
39
51
|
_serialize(state: AnimationState): void;
|
|
@@ -41,6 +53,7 @@ export declare class LayerClip implements Stream {
|
|
|
41
53
|
_restore(state: AnimationState): void;
|
|
42
54
|
get clipTime(): number;
|
|
43
55
|
stop(): void;
|
|
56
|
+
isStalled(): boolean;
|
|
44
57
|
}
|
|
45
58
|
export interface LayerClipSeekOptions {
|
|
46
59
|
fade?: FadeParameters | null;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Event } from '../event';
|
|
2
|
+
import { Observable } from '../observable';
|
|
1
3
|
import { AnimationEvents } from './animation';
|
|
2
4
|
import { StreamState } from './stream';
|
|
3
5
|
import { resolveClipTimeLoops } from './tracks/track';
|
|
@@ -16,52 +18,88 @@ export class LayerClip {
|
|
|
16
18
|
this._rate = 1;
|
|
17
19
|
this._loop = false;
|
|
18
20
|
this._stopped = false;
|
|
19
|
-
this.
|
|
21
|
+
this._state = StreamState.Paused;
|
|
22
|
+
this.state = new Observable(this._state);
|
|
23
|
+
this.playing = new Observable(false);
|
|
24
|
+
this.stalled = new Observable(false);
|
|
25
|
+
this.onPlaying = new Event();
|
|
26
|
+
this.onPaused = new Event();
|
|
27
|
+
this.onEnded = new Event();
|
|
28
|
+
this.onLoop = new Event();
|
|
20
29
|
this._clipDirty = (v) => {
|
|
21
30
|
if (v)
|
|
22
31
|
this._lastClipTime = undefined;
|
|
23
32
|
};
|
|
33
|
+
this._stateUpdate = (s) => {
|
|
34
|
+
this.playing.value = s === StreamState.Playing;
|
|
35
|
+
switch (s) {
|
|
36
|
+
case StreamState.Ended:
|
|
37
|
+
this.onEnded.emit(this);
|
|
38
|
+
break;
|
|
39
|
+
case StreamState.Playing:
|
|
40
|
+
this.onPlaying.emit(this);
|
|
41
|
+
break;
|
|
42
|
+
case StreamState.Paused:
|
|
43
|
+
this.onPaused.emit(this);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
24
47
|
this.animation = layer.animation;
|
|
25
48
|
this._t1 = clip.length;
|
|
26
49
|
layer._registerLayerClip(this);
|
|
27
50
|
this.clip.influencedPathsDirty.addListener(this._clipDirty);
|
|
28
51
|
if (id)
|
|
29
52
|
layer.animation.layerClipByID.set(id, this);
|
|
53
|
+
this.state.addListener(this._stateUpdate);
|
|
30
54
|
}
|
|
31
55
|
tick(touchedPaths, force) {
|
|
32
56
|
const t = this._getTime();
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
if (this._stallStartTime !== undefined) {
|
|
58
|
+
if (!this.clip.isStalled())
|
|
59
|
+
this._cancelStall();
|
|
60
|
+
}
|
|
61
|
+
else if (this._state === StreamState.Playing) {
|
|
62
|
+
if (this.clip.isStalled()) {
|
|
63
|
+
this._stallStartTime = t;
|
|
64
|
+
this.stalled.value = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const t0 = this._t0 + (t - (this._pauseTime ?? t)) + (t - (this._stallStartTime ?? t));
|
|
68
|
+
const t1 = this._t1 + (t - (this._pauseTime ?? t)) + (t - (this._stallStartTime ?? t));
|
|
35
69
|
const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
|
|
36
70
|
this._lastTickTime = ct;
|
|
37
71
|
if (ct !== this._lastClipTime || force) {
|
|
38
72
|
touchedPaths.push(...this.clip.influencedPaths);
|
|
39
73
|
}
|
|
40
|
-
if (this.
|
|
74
|
+
if (this._state === StreamState.Playing && t >= this._t1) {
|
|
41
75
|
this.pause();
|
|
42
|
-
this.
|
|
76
|
+
this._state = StreamState.Ended;
|
|
77
|
+
this.state.value = this._state;
|
|
43
78
|
}
|
|
44
79
|
else {
|
|
45
80
|
const [bt, loop] = resolveClipTimeLoops(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, this.clip.length, this._rate < 0, t1);
|
|
46
|
-
this.clip.streamTick(this.
|
|
81
|
+
this.clip.streamTick(this._state, bt, this._rate, this.layer.active === this, this.layer.active, loop !== this._lastLoop, this._stallStartTime !== undefined, 1);
|
|
82
|
+
const isNewLoop = this._lastLoop !== undefined && this._lastLoop !== loop;
|
|
47
83
|
this._lastLoop = loop;
|
|
84
|
+
if (isNewLoop)
|
|
85
|
+
this.onLoop.emit(this);
|
|
48
86
|
}
|
|
49
87
|
}
|
|
50
88
|
computePathProperty(p, valueBefore) {
|
|
51
89
|
const t = this._getTime();
|
|
52
|
-
const t0 = this._t0 + (t - (this._pauseTime ?? t));
|
|
53
|
-
const t1 = this._t1 + (t - (this._pauseTime ?? t));
|
|
90
|
+
const t0 = this._t0 + (t - (this._pauseTime ?? t)) + (t - (this._stallStartTime ?? t));
|
|
91
|
+
const t1 = this._t1 + (t - (this._pauseTime ?? t)) + (t - (this._stallStartTime ?? t));
|
|
54
92
|
const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
|
|
55
93
|
this._lastClipTime = ct;
|
|
56
94
|
return this.clip.computePathProperty(ct ?? 0, p, valueBefore);
|
|
57
95
|
}
|
|
58
96
|
getRemainingTimeEstimate() {
|
|
59
97
|
const t = this._getTime();
|
|
60
|
-
const t1 = this._t1 + (t - (this._pauseTime ?? t));
|
|
98
|
+
const t1 = this._t1 + (t - (this._pauseTime ?? t)) + (t - (this._stallStartTime ?? t));
|
|
61
99
|
return t1 - t;
|
|
62
100
|
}
|
|
63
101
|
_getTime() {
|
|
64
|
-
return this.timeSource?.() ?? this.animation
|
|
102
|
+
return this.timeSource?.() ?? this.animation?.timeSource?.() ?? performance.now();
|
|
65
103
|
}
|
|
66
104
|
queue(opts) {
|
|
67
105
|
this.layer.queue(this, opts);
|
|
@@ -77,7 +115,7 @@ export class LayerClip {
|
|
|
77
115
|
this._stopped = false;
|
|
78
116
|
this._loop = opts?.loop ?? this.defaultLoop;
|
|
79
117
|
const t = this._getTime();
|
|
80
|
-
if (this.
|
|
118
|
+
if (this._state === StreamState.Ended) {
|
|
81
119
|
this._t0 = t;
|
|
82
120
|
}
|
|
83
121
|
else if (this._pauseTime !== undefined) {
|
|
@@ -100,7 +138,7 @@ export class LayerClip {
|
|
|
100
138
|
}
|
|
101
139
|
const t0 = this._t0 + (t - (this._pauseTime ?? t));
|
|
102
140
|
const t1 = this._t1 + (t - (this._pauseTime ?? t));
|
|
103
|
-
this.
|
|
141
|
+
this._state = StreamState.Playing;
|
|
104
142
|
this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
|
|
105
143
|
this._lastClipTime = undefined;
|
|
106
144
|
this._lastTickTime = undefined;
|
|
@@ -108,18 +146,34 @@ export class LayerClip {
|
|
|
108
146
|
this.layer._activateLayerClip(this, opts);
|
|
109
147
|
this.layer._evaulate();
|
|
110
148
|
}
|
|
149
|
+
if (this.clip.isStalled()) {
|
|
150
|
+
this._stallStartTime = t;
|
|
151
|
+
this.stalled.value = true;
|
|
152
|
+
}
|
|
111
153
|
const [bt, loop] = resolveClipTimeLoops(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, this.clip.length, this._rate < 0, t1);
|
|
112
|
-
this.clip.streamTick(this.
|
|
154
|
+
this.clip.streamTick(this._state, bt, this._rate, this.layer.active === this, this.layer.active, loop !== this._lastLoop, this._stallStartTime !== undefined, 1);
|
|
113
155
|
this._lastLoop = loop;
|
|
156
|
+
this.state.value = this._state;
|
|
114
157
|
}
|
|
115
158
|
pause() {
|
|
116
159
|
delete this._lastLoop;
|
|
117
|
-
if (this._pauseTime !== undefined || this.
|
|
160
|
+
if (this._pauseTime !== undefined || this._state !== StreamState.Playing)
|
|
118
161
|
return;
|
|
119
|
-
this.
|
|
162
|
+
this._state = StreamState.Paused;
|
|
120
163
|
this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
|
|
121
164
|
this._pauseTime = this._getTime();
|
|
165
|
+
this._cancelStall();
|
|
122
166
|
this.clip.streamPause(this.layer.active === this, this.layer.active);
|
|
167
|
+
this.state.value = this._state;
|
|
168
|
+
}
|
|
169
|
+
_cancelStall() {
|
|
170
|
+
if (this._stallStartTime === undefined)
|
|
171
|
+
return;
|
|
172
|
+
const t = this._getTime();
|
|
173
|
+
this._t0 += t - this._stallStartTime;
|
|
174
|
+
this._t1 += t - this._stallStartTime;
|
|
175
|
+
delete this._stallStartTime;
|
|
176
|
+
this.stalled.value = false;
|
|
123
177
|
}
|
|
124
178
|
seek(ct, opts) {
|
|
125
179
|
const t = this._getTime();
|
|
@@ -143,6 +197,7 @@ export class LayerClip {
|
|
|
143
197
|
this.layer._activateLayerClip(this, { fade: opts?.fade });
|
|
144
198
|
}
|
|
145
199
|
delete this._lastLoop;
|
|
200
|
+
delete this._stallStartTime;
|
|
146
201
|
this.clip.streamSeek(ct, this._rate, this.layer.active === this, this.layer.active);
|
|
147
202
|
this.layer._evaulate();
|
|
148
203
|
}
|
|
@@ -161,7 +216,7 @@ export class LayerClip {
|
|
|
161
216
|
rate: this._rate,
|
|
162
217
|
loop: this._loop,
|
|
163
218
|
stopped: this._stopped,
|
|
164
|
-
state: this.
|
|
219
|
+
state: this._state,
|
|
165
220
|
};
|
|
166
221
|
state.byLayerClip[this.id] = ret;
|
|
167
222
|
}
|
|
@@ -179,7 +234,8 @@ export class LayerClip {
|
|
|
179
234
|
this._rate = entry.rate;
|
|
180
235
|
this._loop = entry.loop;
|
|
181
236
|
this._stopped = entry.stopped;
|
|
182
|
-
this.
|
|
237
|
+
this._state = entry.state;
|
|
238
|
+
this.state.value = this._state;
|
|
183
239
|
}
|
|
184
240
|
get clipTime() {
|
|
185
241
|
return this._lastTickTime !== undefined ? this._lastTickTime : this.defaultPlaySpeed > 0 ? 0 : this.clip.length;
|
|
@@ -190,9 +246,14 @@ export class LayerClip {
|
|
|
190
246
|
this._lastClipTime = undefined;
|
|
191
247
|
this._lastTickTime = undefined;
|
|
192
248
|
delete this._lastLoop;
|
|
249
|
+
delete this._stallStartTime;
|
|
193
250
|
this._rate = 1;
|
|
194
251
|
this.clip.streamTick(StreamState.Ended, this._t0, 1, this.layer.active === this, this.layer.active, true);
|
|
195
|
-
this.
|
|
252
|
+
this._state = StreamState.Ended;
|
|
196
253
|
this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
|
|
254
|
+
this.state.value = this._state;
|
|
255
|
+
}
|
|
256
|
+
isStalled() {
|
|
257
|
+
return this._stallStartTime !== undefined;
|
|
197
258
|
}
|
|
198
259
|
}
|
|
@@ -29,6 +29,7 @@ export declare class ClipTrack extends Track {
|
|
|
29
29
|
computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
|
|
30
30
|
streamPause(isActive: boolean, active: LayerClip | null | undefined): void;
|
|
31
31
|
streamSeek(t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined): void;
|
|
32
|
-
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, parentWeight?: number): void;
|
|
32
|
+
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, stalled?: boolean, parentWeight?: number): void;
|
|
33
33
|
private _resolveBlock;
|
|
34
|
+
isStalled(): boolean;
|
|
34
35
|
}
|
|
@@ -79,7 +79,7 @@ export class ClipTrack extends Track {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
-
streamTick(clipState, t, rate, isActive, active, force = false, parentWeight) {
|
|
82
|
+
streamTick(clipState, t, rate, isActive, active, force = false, stalled = false, parentWeight) {
|
|
83
83
|
if (force)
|
|
84
84
|
delete this._lastLoopNumber;
|
|
85
85
|
const block = this._resolveBlock(t, rate);
|
|
@@ -94,7 +94,7 @@ export class ClipTrack extends Track {
|
|
|
94
94
|
this.clip.streamPause(isActive, active);
|
|
95
95
|
}
|
|
96
96
|
else {
|
|
97
|
-
this.clip.streamTick(clipState, bt, rate * block.rate, isActive, active, this._lastLoopNumber !== loopNumber || block !== lastBlock, parentWeight);
|
|
97
|
+
this.clip.streamTick(clipState, bt, rate * block.rate, isActive, active, this._lastLoopNumber !== loopNumber || block !== lastBlock, stalled, parentWeight);
|
|
98
98
|
this._lastLoopNumber = loopNumber;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -113,4 +113,7 @@ export class ClipTrack extends Track {
|
|
|
113
113
|
}
|
|
114
114
|
return undefined;
|
|
115
115
|
}
|
|
116
|
+
isStalled() {
|
|
117
|
+
return this.clip.isStalled();
|
|
118
|
+
}
|
|
116
119
|
}
|
|
@@ -25,7 +25,7 @@ export declare class FunctionTrack extends Track {
|
|
|
25
25
|
}): void;
|
|
26
26
|
get sortedBlocks(): ResolvedFunctionTrackEntity[];
|
|
27
27
|
streamSeek(t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined): void;
|
|
28
|
-
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, parentWeight?: number): void;
|
|
28
|
+
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, stalled?: boolean, parentWeight?: number): void;
|
|
29
29
|
streamPause(isActive: boolean, active: LayerClip | null | undefined): void;
|
|
30
30
|
private _resolveBlocksBetween;
|
|
31
31
|
private _getBoundedT;
|
|
@@ -32,7 +32,7 @@ export class FunctionTrack extends Track {
|
|
|
32
32
|
streamSeek(t, rate, isActive, active) {
|
|
33
33
|
this._lastTick = t;
|
|
34
34
|
}
|
|
35
|
-
streamTick(clipState, t, rate, isActive, active, force = false, parentWeight) {
|
|
35
|
+
streamTick(clipState, t, rate, isActive, active, force = false, stalled = false, parentWeight) {
|
|
36
36
|
// if (clipState !== StreamState.Playing || this._lastTick === undefined) {
|
|
37
37
|
// this._lastTick = t;
|
|
38
38
|
// return;
|
|
@@ -36,7 +36,8 @@ export declare class StreamTrack extends Track {
|
|
|
36
36
|
streamSeek(t: number, resolvedRate: number, isActive: boolean, active: LayerClip | null | undefined): void;
|
|
37
37
|
private _isPlayingInClip;
|
|
38
38
|
private _isPlayingInLayerClip;
|
|
39
|
-
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, parentWeight?: number): void;
|
|
39
|
+
streamTick(clipState: StreamState, t: number, rate: number, isActive: boolean, active: LayerClip | null | undefined, force?: boolean, stalled?: boolean, parentWeight?: number): void;
|
|
40
40
|
private _applyState;
|
|
41
41
|
private _resolveBlock;
|
|
42
|
+
isStalled(): boolean;
|
|
42
43
|
}
|
|
@@ -99,7 +99,7 @@ export class StreamTrack extends Track {
|
|
|
99
99
|
return false;
|
|
100
100
|
return this._isPlayingInClip(stream, layerClip.clip);
|
|
101
101
|
}
|
|
102
|
-
streamTick(clipState, t, rate, isActive, active, force = false, parentWeight) {
|
|
102
|
+
streamTick(clipState, t, rate, isActive, active, force = false, stalled = false, parentWeight) {
|
|
103
103
|
if (!isActive && this._isPlayingInLayerClip(active)) {
|
|
104
104
|
delete this._lastLoopNumber;
|
|
105
105
|
return;
|
|
@@ -110,7 +110,7 @@ export class StreamTrack extends Track {
|
|
|
110
110
|
let desiredState = clipState;
|
|
111
111
|
const lastBlock = this._lastTick === undefined ? undefined : this._resolveBlock(this._lastTick, rate);
|
|
112
112
|
this._lastTick = t;
|
|
113
|
-
if (!block) {
|
|
113
|
+
if (!block || stalled) {
|
|
114
114
|
desiredState = StreamState.Paused;
|
|
115
115
|
}
|
|
116
116
|
else {
|
|
@@ -158,4 +158,7 @@ export class StreamTrack extends Track {
|
|
|
158
158
|
}
|
|
159
159
|
return undefined;
|
|
160
160
|
}
|
|
161
|
+
isStalled() {
|
|
162
|
+
return this.stream?.isStalled?.() ?? false;
|
|
163
|
+
}
|
|
161
164
|
}
|
|
@@ -7,6 +7,7 @@ export declare abstract class Track {
|
|
|
7
7
|
constructor(anim: Animation, id?: string | undefined);
|
|
8
8
|
abstract get influencedPaths(): string[];
|
|
9
9
|
abstract computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
|
|
10
|
+
isStalled(): boolean;
|
|
10
11
|
}
|
|
11
12
|
export declare function resolveKeyframeValue(t: number, before: Keyframe, after: Keyframe | undefined): any;
|
|
12
13
|
export declare function resolveKeyframes(keyframes: Keyframe[], t: number): [before: Keyframe | undefined, after: Keyframe | undefined];
|
package/lib/inflate.js
CHANGED
|
@@ -152,7 +152,17 @@ export function updateClipFromData(zcomp, clip, data) {
|
|
|
152
152
|
clip.defaultFadeParameters = resolvedFadeParameters(data.defaultFadeParameters, zcomp.animation.curves);
|
|
153
153
|
clip.length = data.length;
|
|
154
154
|
clip.clearTracks();
|
|
155
|
-
|
|
155
|
+
const tracks = Object.values(data.tracks);
|
|
156
|
+
tracks.sort((atrack, btrack) => {
|
|
157
|
+
let a = atrack.order ?? 'A0';
|
|
158
|
+
let b = btrack.order ?? 'A0';
|
|
159
|
+
if (a === b) {
|
|
160
|
+
a = atrack.id;
|
|
161
|
+
b = btrack.id;
|
|
162
|
+
}
|
|
163
|
+
return a < b ? -1 : 1;
|
|
164
|
+
});
|
|
165
|
+
for (const track of Object.values(tracks)) {
|
|
156
166
|
if (!track)
|
|
157
167
|
continue;
|
|
158
168
|
const instance = createTrackFromData(zcomp, clip.animation, track);
|
|
@@ -195,7 +205,17 @@ export function populateAnimationTracksFromData(zcomp, anim, data) {
|
|
|
195
205
|
const clip = anim.clipByID.get(clipData.id);
|
|
196
206
|
if (!clip)
|
|
197
207
|
continue;
|
|
198
|
-
|
|
208
|
+
const tracks = Object.values(clipData.tracks);
|
|
209
|
+
tracks.sort((atrack, btrack) => {
|
|
210
|
+
let a = atrack.order ?? 'A0';
|
|
211
|
+
let b = btrack.order ?? 'A0';
|
|
212
|
+
if (a === b) {
|
|
213
|
+
a = atrack.id;
|
|
214
|
+
b = btrack.id;
|
|
215
|
+
}
|
|
216
|
+
return a < b ? -1 : 1;
|
|
217
|
+
});
|
|
218
|
+
for (const track of Object.values(tracks)) {
|
|
199
219
|
if (!track)
|
|
200
220
|
continue;
|
|
201
221
|
const instance = createTrackFromData(zcomp, anim, track);
|
package/lib/observable.d.ts
CHANGED
|
@@ -33,10 +33,10 @@ type Resolved<T, M> = [T] extends [never] ? M : T;
|
|
|
33
33
|
* @typeParam TypeInternal - An internal type used to improve automatic type detection
|
|
34
34
|
*/
|
|
35
35
|
export declare class Observable<Type = never, TypeInternal extends any[] | [] | never = never> extends Emitter<[Resolved<Type, TypeInternal>]> {
|
|
36
|
-
private _default;
|
|
37
36
|
private _deep;
|
|
38
37
|
private _proxies;
|
|
39
38
|
private _value;
|
|
39
|
+
private _default;
|
|
40
40
|
/**
|
|
41
41
|
* Constructs a new Observable
|
|
42
42
|
*
|
package/lib/observable.js
CHANGED
|
@@ -32,21 +32,12 @@ import { Emitter } from "./emitter";
|
|
|
32
32
|
* @typeParam TypeInternal - An internal type used to improve automatic type detection
|
|
33
33
|
*/
|
|
34
34
|
export class Observable extends Emitter {
|
|
35
|
-
constructor(
|
|
35
|
+
constructor(def, withHandler, _deep = true, callWithImmediately = false) {
|
|
36
36
|
super();
|
|
37
|
-
this._default = _default;
|
|
38
37
|
this._deep = _deep;
|
|
39
38
|
this._proxies = new WeakMap();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
initial = this._default.slice();
|
|
43
|
-
this._default = this._default.slice();
|
|
44
|
-
}
|
|
45
|
-
else if (typeof this._default === 'object' && this._deep && this._default !== null && Object.getPrototypeOf(this._default) !== Object.prototype) {
|
|
46
|
-
initial = { ...this._default };
|
|
47
|
-
this._default = { ...this._default };
|
|
48
|
-
}
|
|
49
|
-
this._value = this._wrap(initial);
|
|
39
|
+
this._default = clone(def, _deep);
|
|
40
|
+
this._value = this._wrap(clone(def, _deep));
|
|
50
41
|
if (withHandler)
|
|
51
42
|
this.addListener(withHandler, 0, callWithImmediately);
|
|
52
43
|
}
|
|
@@ -59,48 +50,43 @@ export class Observable extends Emitter {
|
|
|
59
50
|
return this._value.proxy;
|
|
60
51
|
}
|
|
61
52
|
_wrap(v) {
|
|
62
|
-
if (!
|
|
63
|
-
|
|
64
|
-
v === null ||
|
|
65
|
-
Object.getPrototypeOf(v) !== Object.prototype ||
|
|
66
|
-
this._deep === false ||
|
|
67
|
-
typeof v === 'function') {
|
|
68
|
-
return { proxy: v, target: v };
|
|
69
|
-
}
|
|
70
|
-
}
|
|
53
|
+
if (!shouldWrap(v) || !this._deep)
|
|
54
|
+
return { proxy: v, target: v };
|
|
71
55
|
const that = this;
|
|
72
56
|
return {
|
|
73
57
|
target: v,
|
|
74
58
|
proxy: new Proxy(v, {
|
|
75
59
|
get(target, p, receiver) {
|
|
76
60
|
const val = target[p];
|
|
61
|
+
if (!shouldWrap(val))
|
|
62
|
+
return val;
|
|
77
63
|
if (Array.isArray(target) && p === "splice") {
|
|
78
|
-
return function (...args) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (Object.getPrototypeOf(val) !== Object.prototype)
|
|
86
|
-
return val;
|
|
87
|
-
if (typeof val === 'function')
|
|
88
|
-
return val;
|
|
64
|
+
return function (...args) {
|
|
65
|
+
for (let i = 2; i < args.length; i++) {
|
|
66
|
+
args[i] = clone(args[i], true);
|
|
67
|
+
}
|
|
68
|
+
val.apply(target, args);
|
|
69
|
+
that._emitValue();
|
|
70
|
+
};
|
|
89
71
|
}
|
|
90
72
|
if (val['__z_is_observable'])
|
|
91
73
|
return val;
|
|
92
74
|
const proxy = that._proxies.get(val) || that._wrap(val);
|
|
93
75
|
that._proxies.set(val, proxy);
|
|
94
|
-
return proxy;
|
|
76
|
+
return proxy.proxy;
|
|
95
77
|
},
|
|
96
78
|
set(target, p, val) {
|
|
97
|
-
target[p]
|
|
98
|
-
|
|
79
|
+
const changed = target[p] !== val;
|
|
80
|
+
target[p] = clone(val, true);
|
|
81
|
+
if (changed)
|
|
82
|
+
that._emitValue();
|
|
99
83
|
return true;
|
|
100
84
|
},
|
|
101
85
|
deleteProperty(target, p) {
|
|
86
|
+
const changed = target[p] !== undefined;
|
|
102
87
|
delete target[p];
|
|
103
|
-
|
|
88
|
+
if (changed)
|
|
89
|
+
that._emitValue();
|
|
104
90
|
return true;
|
|
105
91
|
}
|
|
106
92
|
})
|
|
@@ -108,13 +94,10 @@ export class Observable extends Emitter {
|
|
|
108
94
|
}
|
|
109
95
|
set value(v) {
|
|
110
96
|
v = v ?? this._default;
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
const changed = v !== this._value.proxy;
|
|
98
|
+
this._value = this._wrap(clone(v, this._deep));
|
|
99
|
+
if (changed)
|
|
113
100
|
this._emitValue();
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
this._value = this._wrap(Array.isArray(v) ? [...v] : v);
|
|
117
|
-
this._emitValue();
|
|
118
101
|
}
|
|
119
102
|
addListener(fn, priority = 0, callImmediately = true) {
|
|
120
103
|
super.addListener(fn);
|
|
@@ -131,3 +114,48 @@ export class Observable extends Emitter {
|
|
|
131
114
|
this._emit(this._value.proxy);
|
|
132
115
|
}
|
|
133
116
|
}
|
|
117
|
+
function clone(a, deep) {
|
|
118
|
+
if (!deep) {
|
|
119
|
+
if (Array.isArray(a))
|
|
120
|
+
a.slice();
|
|
121
|
+
if (typeof a === 'object' && a !== null) {
|
|
122
|
+
const proto = Object.getPrototypeOf(a);
|
|
123
|
+
if (proto === Object.prototype || proto === null) {
|
|
124
|
+
return { ...a };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return a;
|
|
128
|
+
}
|
|
129
|
+
if (Array.isArray(a)) {
|
|
130
|
+
const ret = new Array(a.length);
|
|
131
|
+
for (let i = 0; i < ret.length; i++) {
|
|
132
|
+
ret[i] = clone(a[i], true);
|
|
133
|
+
}
|
|
134
|
+
return ret;
|
|
135
|
+
}
|
|
136
|
+
if (typeof a === 'object' && a !== null) {
|
|
137
|
+
const proto = Object.getPrototypeOf(a);
|
|
138
|
+
if (proto === Object.prototype || proto === null) {
|
|
139
|
+
const ret = Object.create(null);
|
|
140
|
+
for (const entry of Object.getOwnPropertyNames(a)) {
|
|
141
|
+
ret[entry] = clone(a[entry], true);
|
|
142
|
+
}
|
|
143
|
+
return ret;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return a;
|
|
147
|
+
}
|
|
148
|
+
function shouldWrap(a) {
|
|
149
|
+
if (Array.isArray(a))
|
|
150
|
+
return true;
|
|
151
|
+
if (a === null)
|
|
152
|
+
return false;
|
|
153
|
+
if (typeof a === 'object' && a !== null) {
|
|
154
|
+
const proto = Object.getPrototypeOf(a);
|
|
155
|
+
if (proto === Object.prototype || proto === null)
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
if (typeof a === 'function')
|
|
159
|
+
return false;
|
|
160
|
+
return false;
|
|
161
|
+
}
|
package/package.json
CHANGED