@zcomponent/core 0.0.19 → 0.0.21

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.
Files changed (46) hide show
  1. package/lib/animation/animation.d.ts +46 -0
  2. package/lib/animation/animation.js +159 -0
  3. package/lib/animation/animationstate.d.ts +27 -0
  4. package/lib/animation/animationstate.js +1 -0
  5. package/lib/animation/bezier.d.ts +9 -0
  6. package/lib/animation/bezier.js +93 -0
  7. package/lib/animation/clips/clip.d.ts +30 -0
  8. package/lib/animation/clips/clip.js +114 -0
  9. package/lib/animation/index.d.ts +7 -0
  10. package/lib/animation/index.js +7 -0
  11. package/lib/animation/interpolate.d.ts +2 -0
  12. package/lib/animation/interpolate.js +44 -0
  13. package/lib/animation/layer.d.ts +42 -0
  14. package/lib/animation/layer.js +211 -0
  15. package/lib/animation/layerclip.d.ts +46 -0
  16. package/lib/animation/layerclip.js +168 -0
  17. package/lib/animation/stream.d.ts +15 -0
  18. package/lib/animation/stream.js +6 -0
  19. package/lib/animation/tracks/cliptrack.d.ts +25 -0
  20. package/lib/animation/tracks/cliptrack.js +68 -0
  21. package/lib/animation/tracks/propertytrack.d.ts +32 -0
  22. package/lib/animation/tracks/propertytrack.js +79 -0
  23. package/lib/animation/tracks/track.d.ts +10 -0
  24. package/lib/animation/tracks/track.js +30 -0
  25. package/lib/animation.d.ts +86 -65
  26. package/lib/animation.js +83 -1
  27. package/lib/behaviors/PauseLayerClip.d.ts +20 -0
  28. package/lib/behaviors/PauseLayerClip.js +26 -0
  29. package/lib/behaviors/PlayLayerClip.d.ts +78 -0
  30. package/lib/behaviors/PlayLayerClip.js +62 -0
  31. package/lib/behaviors/SetLayerOff.d.ts +20 -0
  32. package/lib/behaviors/SetLayerOff.js +26 -0
  33. package/lib/data.d.ts +3 -2
  34. package/lib/data.js +8 -5
  35. package/lib/index.d.ts +1 -0
  36. package/lib/index.js +1 -0
  37. package/lib/inflate.d.ts +13 -0
  38. package/lib/inflate.js +185 -0
  39. package/lib/interfaces.d.ts +1 -0
  40. package/lib/selectors.d.ts +5 -0
  41. package/lib/selectors.js +14 -0
  42. package/lib/types.d.ts +22 -2
  43. package/lib/types.js +41 -15
  44. package/lib/zcomponent.d.ts +11 -0
  45. package/lib/zcomponent.js +35 -0
  46. package/package.json +2 -1
@@ -0,0 +1,211 @@
1
+ import { Observable } from '../observable';
2
+ import { AnimationEvents } from './animation';
3
+ import { computeEasing } from './bezier';
4
+ import { interpolate } from './interpolate';
5
+ import { StreamState } from './stream';
6
+ export class Layer {
7
+ constructor(animation) {
8
+ this.animation = animation;
9
+ this.influencedPathsDirty = new Observable(false);
10
+ this._influencedPaths = new Set();
11
+ this._active = null;
12
+ this._queue = [];
13
+ this._layerClips = [];
14
+ }
15
+ computePathProperty(t, p, valueBefore) {
16
+ let fadeValue = valueBefore;
17
+ for (let i = 0; i < this._queue.length; i++) {
18
+ const entry = this._queue[i];
19
+ const clipValue = entry.layerClip?.computePathProperty(p, valueBefore) ?? valueBefore;
20
+ if (entry.startTime && entry.fadeTime > 0 && entry.playOptions?.fade !== null) {
21
+ const ct = t - entry.startTime;
22
+ if (ct >= entry.fadeTime)
23
+ fadeValue = clipValue;
24
+ else
25
+ fadeValue = computeFade(entry.fadeByPath[p], entry.playOptions?.fade, ct, entry.fadeTime, fadeValue, clipValue);
26
+ }
27
+ else {
28
+ fadeValue = clipValue;
29
+ }
30
+ if (entry === this._active)
31
+ break;
32
+ }
33
+ return fadeValue;
34
+ }
35
+ tick(t, touchedPaths) {
36
+ for (let i = this._queue.length - 1; i >= 0; i--) {
37
+ const entry = this._queue[i];
38
+ const next = this._queue[i + 1];
39
+ entry.layerClip?.tick(touchedPaths, this._queue.length > 1);
40
+ if (next && next.startTime && next.startTime && entry !== this._active && t - next.startTime > next.fadeTime) {
41
+ entry.layerClip?.pause();
42
+ this._queue.splice(i, 1);
43
+ }
44
+ if (entry.layerClip && entry === this._active) {
45
+ if (next && (entry.layerClip.state === StreamState.Ended || next.fadeTime >= entry.layerClip.getRemainingTimeEstimate())) {
46
+ next.startTime = t;
47
+ this._active = next;
48
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipActive, args: [this._active.layerClip] });
49
+ next.layerClip?.play();
50
+ }
51
+ }
52
+ }
53
+ }
54
+ pause() {
55
+ if (!this._active)
56
+ return;
57
+ this._active.layerClip?.pause();
58
+ }
59
+ /** @internal */
60
+ _registerLayerClip(layerClip) {
61
+ this._layerClips.push(layerClip);
62
+ layerClip.clip.influencedPathsDirty.addListener(v => {
63
+ if (v)
64
+ this.influencedPathsDirty.value = true;
65
+ });
66
+ this.influencedPathsDirty.value = true;
67
+ }
68
+ queue(layerClip, playOptions) {
69
+ const previous = this._queue[this._queue.length - 1];
70
+ const fadeByPath = {};
71
+ previous?.layerClip?.clip?.fadePropertiesByPath(fadeByPath);
72
+ for (const [path, params] of Object.entries(fadeByPath)) {
73
+ fadeByPath[path] = {
74
+ ...params,
75
+ reverse: !(params.reverse ?? false),
76
+ };
77
+ }
78
+ layerClip?.clip?.fadePropertiesByPath(fadeByPath);
79
+ let fadeTime = playOptions?.fade?.time ?? 0;
80
+ for (const params of Object.values(fadeByPath)) {
81
+ fadeTime = Math.max(fadeTime, params.time);
82
+ }
83
+ const ret = {
84
+ layerClip,
85
+ fadeTime,
86
+ playOptions,
87
+ fadeByPath,
88
+ };
89
+ this._queue.push(ret);
90
+ return ret;
91
+ }
92
+ get active() {
93
+ return this._active?.layerClip;
94
+ }
95
+ set active(layerClip) {
96
+ this._activateLayerClip(layerClip);
97
+ this._evaulate();
98
+ }
99
+ /** @internal */
100
+ _activateLayerClip(layerClip, playOptions) {
101
+ if (layerClip === undefined) {
102
+ this._queue = [];
103
+ this._active = undefined;
104
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipActive, args: [undefined] });
105
+ return;
106
+ }
107
+ if (this._active && this._active.layerClip === layerClip)
108
+ return;
109
+ for (let i = 0; i < this._queue.length; i++) {
110
+ const entry = this._queue[i];
111
+ if (entry === this._active) {
112
+ this._queue.splice(i + 1);
113
+ break;
114
+ }
115
+ }
116
+ const entry = this.queue(layerClip, {
117
+ ...playOptions,
118
+ fade: playOptions?.fade !== undefined ? playOptions.fade : this._active === undefined || layerClip === undefined ? { time: 0, easing: null } : undefined,
119
+ });
120
+ this._active = entry;
121
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipActive, args: [this._active.layerClip] });
122
+ this._queue[this._queue.length - 1].startTime = this.animation.timeSource?.() ?? performance.now();
123
+ }
124
+ /** @internal */
125
+ _evaulate() {
126
+ this.animation.evaluateTouchedPaths([...this.influencedPaths.values()]);
127
+ }
128
+ /** @internal */
129
+ _serialize(state) {
130
+ for (const layerClip of this._layerClips) {
131
+ layerClip._serialize(state);
132
+ }
133
+ if (this.id === undefined)
134
+ return;
135
+ const entry = {
136
+ queue: [],
137
+ };
138
+ for (const queueEntry of this._queue) {
139
+ if (queueEntry.layerClip && queueEntry.layerClip.id === undefined)
140
+ continue;
141
+ entry.queue.push({
142
+ ...queueEntry,
143
+ layerClip: queueEntry.layerClip === null ? null : queueEntry.layerClip?.id,
144
+ });
145
+ }
146
+ entry.active = this._active === null ? null : this._active === undefined ? undefined : this._queue.indexOf(this._active);
147
+ state.byLayer[this.id] = entry;
148
+ }
149
+ /** @internal */
150
+ _restore(state) {
151
+ for (const layerClip of this._layerClips) {
152
+ layerClip._restore(state);
153
+ }
154
+ if (this.id === undefined)
155
+ return;
156
+ const entry = state.byLayer[this.id];
157
+ if (!entry)
158
+ return;
159
+ this._queue = [];
160
+ for (const qe of entry.queue) {
161
+ let layerClip;
162
+ if (typeof qe.layerClip === 'string') {
163
+ layerClip = this._layerClips.find(lc => lc.id === qe.layerClip);
164
+ }
165
+ else if (qe.layerClip === null)
166
+ layerClip = null;
167
+ if (layerClip !== undefined) {
168
+ this._queue.push({
169
+ ...qe,
170
+ layerClip,
171
+ });
172
+ }
173
+ }
174
+ if (typeof entry.active === 'number') {
175
+ this._active = this._queue[entry.active];
176
+ }
177
+ else
178
+ this._active = entry.active;
179
+ }
180
+ get influencedPaths() {
181
+ if (!this.influencedPathsDirty.value)
182
+ return this._influencedPaths;
183
+ this._influencedPaths = new Set();
184
+ for (const layerClip of this._layerClips) {
185
+ layerClip.clip.influencedPaths.forEach(path => this._influencedPaths.add(path));
186
+ }
187
+ this.influencedPathsDirty.value = false;
188
+ return this._influencedPaths;
189
+ }
190
+ }
191
+ function computeFade(params, override, t, fadeTime, before, after) {
192
+ // TODO further implementation
193
+ const paramTime = override?.time ?? params?.time ?? 0;
194
+ let paramPin = override?.pin ?? params?.pin ?? 0;
195
+ const reverse = override?.reverse ?? params?.reverse ?? false;
196
+ if (reverse)
197
+ paramPin = 1 - paramPin;
198
+ const emptyTime = fadeTime - paramTime;
199
+ const startTime = paramPin * emptyTime;
200
+ if (t < startTime)
201
+ return before;
202
+ if (t >= startTime + paramTime)
203
+ return after;
204
+ let prop = (t - startTime) / paramTime;
205
+ if (reverse)
206
+ prop = 1 - prop;
207
+ prop = computeEasing(prop, override?.easing ?? params?.easing);
208
+ if (reverse)
209
+ prop = 1 - prop;
210
+ return interpolate(before, after, prop);
211
+ }
@@ -0,0 +1,46 @@
1
+ import { FadeParameters } from '../animation';
2
+ import { Animation } from './animation';
3
+ import { AnimationState } from './animationstate';
4
+ import { Clip } from './clips/clip';
5
+ import { Layer } from './layer';
6
+ import { PlayOptions, Stream, StreamState } from './stream';
7
+ export declare class LayerClip implements Stream {
8
+ readonly layer: Layer;
9
+ readonly clip: Clip;
10
+ id?: string;
11
+ defaultLoop: boolean;
12
+ defaultPlaySpeed: number;
13
+ timeSource: (() => number) | undefined;
14
+ readonly animation: Animation;
15
+ private _t0;
16
+ private _pauseTime;
17
+ private _t1;
18
+ private _rate;
19
+ private _loop;
20
+ private _lastClipTime;
21
+ private _stopped;
22
+ state: StreamState;
23
+ constructor(layer: Layer, clip: Clip);
24
+ private _clipDirty;
25
+ tick(touchedPaths: string[], force?: boolean): void;
26
+ computePathProperty(p: string, valueBefore: any): any;
27
+ getRemainingTimeEstimate(): number;
28
+ private _getTime;
29
+ queue(opts?: LayerClipPlayOptions): void;
30
+ play(opts?: LayerClipPlayOptions): void;
31
+ pause(): void;
32
+ seek(ct: number, opts?: LayerClipSeekOptions): void;
33
+ /** @internal */
34
+ _serialize(state: AnimationState): void;
35
+ /** @internal */
36
+ _restore(state: AnimationState): void;
37
+ get clipTime(): number;
38
+ stop(): void;
39
+ }
40
+ export interface LayerClipSeekOptions {
41
+ fade?: FadeParameters | null;
42
+ dontActivateLayer?: boolean;
43
+ }
44
+ export interface LayerClipPlayOptions extends PlayOptions {
45
+ fade?: Partial<FadeParameters> | null;
46
+ }
@@ -0,0 +1,168 @@
1
+ import { AnimationEvents } from './animation';
2
+ import { StreamState } from './stream';
3
+ export class LayerClip {
4
+ constructor(layer, clip) {
5
+ this.layer = layer;
6
+ this.clip = clip;
7
+ this.defaultLoop = false;
8
+ this.defaultPlaySpeed = 1;
9
+ this._t0 = 0;
10
+ this._pauseTime = 0;
11
+ // private _s0: number = 0;
12
+ this._rate = 1;
13
+ this._loop = false;
14
+ this._stopped = false;
15
+ this.state = StreamState.Paused;
16
+ this._clipDirty = (v) => {
17
+ if (v)
18
+ this._lastClipTime = undefined;
19
+ };
20
+ this.animation = layer.animation;
21
+ this._t1 = clip.length;
22
+ layer._registerLayerClip(this);
23
+ this.clip.influencedPathsDirty.addListener(this._clipDirty);
24
+ }
25
+ tick(touchedPaths, force) {
26
+ const t = this._getTime();
27
+ const t0 = this._t0 + (t - (this._pauseTime ?? t));
28
+ const t1 = this._t1 + (t - (this._pauseTime ?? t));
29
+ const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
30
+ if (ct !== this._lastClipTime || force) {
31
+ touchedPaths.push(...this.clip.influencedPaths);
32
+ }
33
+ if (this.state === StreamState.Playing && t >= this._t1) {
34
+ this.pause();
35
+ this.state = StreamState.Ended;
36
+ }
37
+ }
38
+ computePathProperty(p, valueBefore) {
39
+ const t = this._getTime();
40
+ const t0 = this._t0 + (t - (this._pauseTime ?? t));
41
+ const t1 = this._t1 + (t - (this._pauseTime ?? t));
42
+ const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
43
+ this._lastClipTime = ct;
44
+ return this.clip.computePathProperty(ct ?? 0, p, valueBefore);
45
+ }
46
+ getRemainingTimeEstimate() {
47
+ const t = this._getTime();
48
+ const t1 = this._t1 + (t - (this._pauseTime ?? t));
49
+ return t1 - t;
50
+ }
51
+ _getTime() {
52
+ return this.timeSource?.() ?? this.animation.timeSource?.() ?? performance.now();
53
+ }
54
+ queue(opts) {
55
+ this.layer.queue(this, opts);
56
+ }
57
+ play(opts) {
58
+ if (opts?.speed === 0) {
59
+ this.pause();
60
+ return;
61
+ }
62
+ this._stopped = false;
63
+ this._loop = opts?.loop ?? this.defaultLoop;
64
+ this._rate = opts?.speed ?? this.defaultPlaySpeed;
65
+ if (this.state === StreamState.Ended) {
66
+ this._t0 = this._getTime();
67
+ }
68
+ else if (this._pauseTime !== undefined) {
69
+ this._t0 = this._getTime() - (this._pauseTime - this._t0);
70
+ }
71
+ delete this._pauseTime;
72
+ if (this._loop)
73
+ this._t1 = Infinity;
74
+ else {
75
+ if (this._rate < 0)
76
+ this._t1 = this._t0 + this.clip.length / -this._rate;
77
+ else if (this._rate > 0)
78
+ this._t1 = this._t0 + this.clip.length / this._rate;
79
+ else
80
+ this._t1 = Infinity;
81
+ }
82
+ this.clip.streamPlay(this._rate);
83
+ this.state = StreamState.Playing;
84
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
85
+ this._lastClipTime = undefined;
86
+ if (this.layer.active !== this) {
87
+ this.layer._activateLayerClip(this, opts);
88
+ this.layer._evaulate();
89
+ }
90
+ }
91
+ pause() {
92
+ if (this._pauseTime !== undefined || this.state !== StreamState.Playing)
93
+ return;
94
+ this.state = StreamState.Paused;
95
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
96
+ this._pauseTime = this._getTime();
97
+ this.clip.streamPause();
98
+ }
99
+ seek(ct, opts) {
100
+ const t = this._getTime();
101
+ this._stopped = false;
102
+ if (this._rate >= 0) {
103
+ this._t0 = t - ct / this._rate;
104
+ this._t1 = this._t0 + this.clip.length / this._rate;
105
+ }
106
+ else {
107
+ this._t0 = t - (this.clip.length - ct) / -this._rate;
108
+ this._t1 = this._t0 + this.clip.length / -this._rate;
109
+ }
110
+ if (this._pauseTime !== undefined) {
111
+ this._pauseTime = t;
112
+ }
113
+ if (this._loop)
114
+ this._t1 = Infinity;
115
+ this._lastClipTime = undefined;
116
+ if (this.layer.active !== this && !opts?.dontActivateLayer) {
117
+ this.layer._activateLayerClip(this, { fade: opts?.fade });
118
+ }
119
+ this.layer._evaulate();
120
+ }
121
+ /** @internal */
122
+ _serialize(state) {
123
+ if (this.id === undefined)
124
+ return;
125
+ const timeOfSerialization = this._getTime();
126
+ const t0 = timeOfSerialization - this._t0;
127
+ const pauseTime = this._pauseTime === undefined ? undefined : timeOfSerialization - this._pauseTime;
128
+ const t1 = isFinite(this._t1) ? timeOfSerialization - this._t1 : null;
129
+ const ret = {
130
+ t0,
131
+ t1,
132
+ pauseTime,
133
+ rate: this._rate,
134
+ loop: this._loop,
135
+ stopped: this._stopped,
136
+ state: this.state,
137
+ };
138
+ state.byLayerClip[this.id] = ret;
139
+ }
140
+ /** @internal */
141
+ _restore(state) {
142
+ if (this.id === undefined)
143
+ return;
144
+ const entry = state.byLayerClip[this.id];
145
+ if (!entry)
146
+ return;
147
+ const timeOfDeserialization = this._getTime();
148
+ this._t0 = timeOfDeserialization - entry.t0;
149
+ this._t1 = entry.t1 === null ? Infinity : timeOfDeserialization - entry.t1;
150
+ this._pauseTime = entry.pauseTime === undefined ? undefined : timeOfDeserialization - entry.pauseTime;
151
+ this._rate = entry.rate;
152
+ this._loop = entry.loop;
153
+ this._stopped = entry.stopped;
154
+ this.state = entry.state;
155
+ }
156
+ get clipTime() {
157
+ return this._lastClipTime !== undefined ? this._lastClipTime : this.defaultPlaySpeed > 0 ? 0 : this.clip.length;
158
+ }
159
+ stop() {
160
+ this._stopped = true;
161
+ this._pauseTime = this._t0;
162
+ this._lastClipTime = undefined;
163
+ this._rate = 1;
164
+ this.clip.streamStop();
165
+ this.state = StreamState.Ended;
166
+ this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
167
+ }
168
+ }
@@ -0,0 +1,15 @@
1
+ export declare enum StreamState {
2
+ 'Playing' = "Playing",
3
+ 'Paused' = "Paused",
4
+ 'Ended' = "Ended"
5
+ }
6
+ export interface Stream {
7
+ play: (opts?: PlayOptions) => void;
8
+ pause: () => void;
9
+ seek: (t: number) => void;
10
+ stop: () => void;
11
+ }
12
+ export interface PlayOptions {
13
+ speed?: number;
14
+ loop?: boolean;
15
+ }
@@ -0,0 +1,6 @@
1
+ export var StreamState;
2
+ (function (StreamState) {
3
+ StreamState["Playing"] = "Playing";
4
+ StreamState["Paused"] = "Paused";
5
+ StreamState["Ended"] = "Ended";
6
+ })(StreamState || (StreamState = {}));
@@ -0,0 +1,25 @@
1
+ import { Keyframe, ClipTrackEntity } from '../../animation';
2
+ import { Clip } from '../clips/clip';
3
+ import { Track } from './track';
4
+ export declare class ClipTrack extends Track {
5
+ readonly clip: Clip;
6
+ private _weights;
7
+ private _weightsById;
8
+ private _weightsDirty;
9
+ private _entities;
10
+ private _entitiesById;
11
+ private _entitiesDirty;
12
+ constructor(clip: Clip);
13
+ get influencedPaths(): string[];
14
+ addWeight(k: Keyframe): void;
15
+ setWeightsById(weights: {
16
+ [id: string]: Keyframe;
17
+ }): void;
18
+ get sortedWeights(): Keyframe[];
19
+ addBlock(k: ClipTrackEntity): void;
20
+ setBlocksById(weights: {
21
+ [id: string]: ClipTrackEntity;
22
+ }): void;
23
+ get sortedBlocks(): ClipTrackEntity[];
24
+ computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
25
+ }
@@ -0,0 +1,68 @@
1
+ import { resolveKeyframes, resolveKeyframeValue, Track } from './track';
2
+ export class ClipTrack extends Track {
3
+ constructor(clip) {
4
+ super();
5
+ this.clip = clip;
6
+ this._weights = [];
7
+ this._weightsById = {};
8
+ this._weightsDirty = false;
9
+ this._entities = [];
10
+ this._entitiesById = {};
11
+ this._entitiesDirty = false;
12
+ this.clip.influencedPathsDirty.addListener(v => {
13
+ if (v)
14
+ this.influencedPathsDirty.value = true;
15
+ });
16
+ }
17
+ get influencedPaths() {
18
+ return this.clip.influencedPaths;
19
+ }
20
+ addWeight(k) {
21
+ this._weightsById[k.id] = k;
22
+ this._weightsDirty = true;
23
+ }
24
+ setWeightsById(weights) {
25
+ this._weightsById = weights;
26
+ this._weightsDirty = true;
27
+ }
28
+ get sortedWeights() {
29
+ if (!this._weightsDirty)
30
+ return this._weights;
31
+ this._weights = Object.values(this._weightsById);
32
+ this._weights.sort((a, b) => a.t - b.t);
33
+ this._weightsDirty = false;
34
+ return this._weights;
35
+ }
36
+ addBlock(k) {
37
+ this._entitiesById[k.id] = k;
38
+ this._entitiesDirty = true;
39
+ }
40
+ setBlocksById(weights) {
41
+ this._entitiesById = weights;
42
+ this._entitiesDirty = true;
43
+ }
44
+ get sortedBlocks() {
45
+ if (!this._entitiesDirty)
46
+ return this._entities;
47
+ this._entities = Object.values(this._entitiesById);
48
+ this._entities.sort((a, b) => a.t0 - b.t0);
49
+ this._entitiesDirty = false;
50
+ return this._entities;
51
+ }
52
+ computePathProperty(t, p, valueBefore, parentWeight) {
53
+ let weight = 1;
54
+ const [weightBefore, weightAfter] = resolveKeyframes(this.sortedWeights, t);
55
+ if (weightBefore)
56
+ weight = resolveKeyframeValue(t, weightBefore, weightAfter);
57
+ weight *= parentWeight ?? 1;
58
+ const blocks = this.sortedBlocks;
59
+ for (let i = blocks.length - 1; i >= 0; i--) {
60
+ const block = blocks[i];
61
+ if (block.t0 > t)
62
+ continue;
63
+ const ct = this.clip.resolveClipTime(t, block.t0, block.s0, block.rate, block.t1);
64
+ return this.clip.computePathProperty(ct, p, valueBefore, weight);
65
+ }
66
+ return valueBefore;
67
+ }
68
+ }
@@ -0,0 +1,32 @@
1
+ import { FadeParameters, Keyframe, BlendType } from '../../animation';
2
+ import { Animation } from '../animation';
3
+ import { Track } from './track';
4
+ export declare class PropertyTrack extends Track {
5
+ private _entityID;
6
+ private _entity;
7
+ path: string;
8
+ private _property;
9
+ private _keyframes;
10
+ private _keyframesById;
11
+ private _keyframesDirty;
12
+ private _weights;
13
+ private _weightsById;
14
+ private _weightsDirty;
15
+ fadeParameters?: Partial<FadeParameters>;
16
+ blend: BlendType;
17
+ influencedPaths: string[];
18
+ constructor(anim: Animation, _entityID: string, _entity: any, property: string | number | (string | number)[]);
19
+ addKeyframe(k: Keyframe): void;
20
+ getKeyframeById(id: string): Keyframe | undefined;
21
+ setKeyframesById(keyframes: {
22
+ [id: string]: Keyframe;
23
+ }): void;
24
+ get sortedKeyframes(): Keyframe[];
25
+ addWeight(k: Keyframe): void;
26
+ setWeightsById(weights: {
27
+ [id: string]: Keyframe;
28
+ }): void;
29
+ get sortedWeights(): Keyframe[];
30
+ getFadeLengthForPath(path: string): number;
31
+ computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
32
+ }
@@ -0,0 +1,79 @@
1
+ import { addBlend, interpolate } from '../interpolate';
2
+ import { resolveKeyframes, resolveKeyframeValue, Track } from './track';
3
+ export class PropertyTrack extends Track {
4
+ constructor(anim, _entityID, _entity, property) {
5
+ super();
6
+ this._entityID = _entityID;
7
+ this._entity = _entity;
8
+ this._keyframes = [];
9
+ this._keyframesById = {};
10
+ this._keyframesDirty = false;
11
+ this._weights = [];
12
+ this._weightsById = {};
13
+ this._weightsDirty = false;
14
+ this.blend = 'overlay';
15
+ if (Array.isArray(property))
16
+ this._property = property;
17
+ else
18
+ this._property = [property];
19
+ this.path = [this._entityID, ...this._property].join('.');
20
+ this.influencedPaths = [this.path];
21
+ anim.registerEntityPath(this.path, this._entity, this._property);
22
+ }
23
+ addKeyframe(k) {
24
+ this._keyframesById[k.id] = k;
25
+ this._keyframesDirty = true;
26
+ }
27
+ getKeyframeById(id) {
28
+ return this._keyframesById[id];
29
+ }
30
+ setKeyframesById(keyframes) {
31
+ this._keyframesById = keyframes;
32
+ this._keyframesDirty = true;
33
+ }
34
+ get sortedKeyframes() {
35
+ if (!this._keyframesDirty)
36
+ return this._keyframes;
37
+ this._keyframes = Object.values(this._keyframesById);
38
+ this._keyframes.sort((a, b) => a.t - b.t);
39
+ this._keyframesDirty = false;
40
+ return this._keyframes;
41
+ }
42
+ addWeight(k) {
43
+ this._weightsById[k.id] = k;
44
+ this._weightsDirty = true;
45
+ }
46
+ setWeightsById(weights) {
47
+ this._weightsById = weights;
48
+ this._weightsDirty = true;
49
+ }
50
+ get sortedWeights() {
51
+ if (!this._weightsDirty)
52
+ return this._weights;
53
+ this._weights = Object.values(this._weightsById);
54
+ this._weights.sort((a, b) => a.t - b.t);
55
+ this._weightsDirty = false;
56
+ return this._weights;
57
+ }
58
+ getFadeLengthForPath(path) {
59
+ return this.fadeParameters?.time ?? 0;
60
+ }
61
+ computePathProperty(t, p, valueBefore, parentWeight) {
62
+ const keyframes = this.sortedKeyframes;
63
+ const [before, after] = resolveKeyframes(keyframes, t);
64
+ if (!before)
65
+ return valueBefore; // Automatic weight 0 before first keyframe
66
+ const val = resolveKeyframeValue(t, before, after);
67
+ let weight = 1;
68
+ const [weightBefore, weightAfter] = resolveKeyframes(this.sortedWeights, t);
69
+ if (weightBefore)
70
+ weight = resolveKeyframeValue(t, weightBefore, weightAfter);
71
+ weight *= parentWeight ?? 1;
72
+ switch (this.blend) {
73
+ case 'add':
74
+ return addBlend(valueBefore, val, weight);
75
+ case 'overlay':
76
+ return interpolate(valueBefore, val, weight);
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,10 @@
1
+ import { Keyframe } from '../../animation';
2
+ import { Observable } from '../../observable';
3
+ export declare abstract class Track {
4
+ influencedPathsDirty: Observable<boolean, never>;
5
+ constructor();
6
+ abstract get influencedPaths(): string[];
7
+ abstract computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
8
+ }
9
+ export declare function resolveKeyframeValue(t: number, before: Keyframe, after: Keyframe | undefined): any;
10
+ export declare function resolveKeyframes(keyframes: Keyframe[], t: number): [before: Keyframe | undefined, after: Keyframe | undefined];