@zcomponent/core 1.0.0 → 1.2.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.
@@ -1,6 +1,7 @@
1
1
  import * as Data from '../../data';
2
2
  import { Observable } from '../../observable';
3
3
  import { Animation } from '../animation';
4
+ import { StreamState } from '../stream';
4
5
  import { Track } from '../tracks/track';
5
6
  export declare class Clip {
6
7
  animation: Animation;
@@ -13,6 +14,7 @@ export declare class Clip {
13
14
  private _tracksByPath;
14
15
  private _tracksByPathDirty;
15
16
  private _tracks;
17
+ private _streamTracks;
16
18
  constructor(animation: Animation, length: number, scriptName?: string | undefined, id?: string | undefined);
17
19
  computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
18
20
  addTrack(t: Track): void;
@@ -24,8 +26,7 @@ export declare class Clip {
24
26
  [id: string]: Partial<Data.FadeParameters>;
25
27
  }): void;
26
28
  resolveClipTime(t: number, t0: number, s0: number, rate: number, t1?: number): number;
27
- streamPlay(speed?: number): void;
28
29
  streamPause(): void;
29
- streamStop(): void;
30
30
  streamSeek(t: number): void;
31
+ streamTick(state: StreamState, ct: number, rate: number, force?: boolean, parentWeight?: number): void;
31
32
  }
@@ -1,6 +1,7 @@
1
1
  import { Observable } from '../../observable';
2
2
  import { ClipTrack } from '../tracks/cliptrack';
3
3
  import { PropertyTrack } from '../tracks/propertytrack';
4
+ import { StreamTrack } from '../tracks/streamtrack';
4
5
  export class Clip {
5
6
  constructor(animation, length, scriptName, id) {
6
7
  this.animation = animation;
@@ -12,6 +13,7 @@ export class Clip {
12
13
  this._tracksByPath = new Map();
13
14
  this._tracksByPathDirty = false;
14
15
  this._tracks = [];
16
+ this._streamTracks = [];
15
17
  this._dirty = (v) => {
16
18
  if (v) {
17
19
  this.influencedPathsDirty.value = true;
@@ -35,6 +37,8 @@ export class Clip {
35
37
  t.influencedPathsDirty.addListener(this._dirty);
36
38
  this.influencedPathsDirty.value = true;
37
39
  this._tracksByPathDirty = true;
40
+ if (t instanceof StreamTrack || t instanceof ClipTrack)
41
+ this._streamTracks.push(t);
38
42
  }
39
43
  clearTracks() {
40
44
  const existingPaths = this._influencedPaths;
@@ -44,6 +48,7 @@ export class Clip {
44
48
  this._tracks = [];
45
49
  this.influencedPathsDirty.value = true;
46
50
  this._tracksByPathDirty = true;
51
+ this._streamTracks = [];
47
52
  this.animation.evaluateTouchedPaths(existingPaths);
48
53
  }
49
54
  get tracksByPath() {
@@ -108,8 +113,19 @@ export class Clip {
108
113
  bounded += this.length;
109
114
  return bounded;
110
115
  }
111
- streamPlay(speed) { }
112
- streamPause() { }
113
- streamStop() { }
114
- streamSeek(t) { }
116
+ streamPause() {
117
+ for (const track of this._streamTracks) {
118
+ track.streamPause();
119
+ }
120
+ }
121
+ streamSeek(t) {
122
+ for (const track of this._streamTracks) {
123
+ track.streamSeek(t);
124
+ }
125
+ }
126
+ streamTick(state, ct, rate, force = false, parentWeight) {
127
+ for (const track of this._streamTracks) {
128
+ track.streamTick(state, ct, rate, force, parentWeight);
129
+ }
130
+ }
115
131
  }
@@ -5,3 +5,4 @@ export * from './tracks/track';
5
5
  export * from './tracks/cliptrack';
6
6
  export * from './tracks/propertytrack';
7
7
  export * from './clips/clip';
8
+ export * from './stream';
@@ -5,3 +5,4 @@ export * from './tracks/track';
5
5
  export * from './tracks/cliptrack';
6
6
  export * from './tracks/propertytrack';
7
7
  export * from './clips/clip';
8
+ export * from './stream';
@@ -19,6 +19,7 @@ export declare class LayerClip implements Stream {
19
19
  private _t1;
20
20
  private _rate;
21
21
  private _loop;
22
+ private _lastTickTime;
22
23
  private _lastClipTime;
23
24
  private _stopped;
24
25
  state: StreamState;
@@ -29,6 +30,7 @@ export declare class LayerClip implements Stream {
29
30
  getRemainingTimeEstimate(): number;
30
31
  private _getTime;
31
32
  queue(opts?: LayerClipPlayOptions): void;
33
+ length(): number;
32
34
  play(opts?: LayerClipPlayOptions): void;
33
35
  pause(): void;
34
36
  seek(ct: number, opts?: LayerClipSeekOptions): void;
@@ -32,6 +32,7 @@ export class LayerClip {
32
32
  const t0 = this._t0 + (t - (this._pauseTime ?? t));
33
33
  const t1 = this._t1 + (t - (this._pauseTime ?? t));
34
34
  const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
35
+ this._lastTickTime = ct;
35
36
  if (ct !== this._lastClipTime || force) {
36
37
  touchedPaths.push(...this.clip.influencedPaths);
37
38
  }
@@ -39,6 +40,7 @@ export class LayerClip {
39
40
  this.pause();
40
41
  this.state = StreamState.Ended;
41
42
  }
43
+ this.clip.streamTick(this.state, ct, this._rate);
42
44
  }
43
45
  computePathProperty(p, valueBefore) {
44
46
  const t = this._getTime();
@@ -59,6 +61,9 @@ export class LayerClip {
59
61
  queue(opts) {
60
62
  this.layer.queue(this, opts);
61
63
  }
64
+ length() {
65
+ return this.clip.length;
66
+ }
62
67
  play(opts) {
63
68
  if (opts?.speed === 0) {
64
69
  this.pause();
@@ -67,11 +72,12 @@ export class LayerClip {
67
72
  this._stopped = false;
68
73
  this._loop = opts?.loop ?? this.defaultLoop;
69
74
  this._rate = opts?.speed ?? this.defaultPlaySpeed;
75
+ const t = this._getTime();
70
76
  if (this.state === StreamState.Ended) {
71
- this._t0 = this._getTime();
77
+ this._t0 = t;
72
78
  }
73
79
  else if (this._pauseTime !== undefined) {
74
- this._t0 = this._getTime() - (this._pauseTime - this._t0);
80
+ this._t0 = t - (this._pauseTime - this._t0);
75
81
  }
76
82
  delete this._pauseTime;
77
83
  if (this._loop)
@@ -84,10 +90,14 @@ export class LayerClip {
84
90
  else
85
91
  this._t1 = Infinity;
86
92
  }
87
- this.clip.streamPlay(this._rate);
93
+ const t0 = this._t0 + (t - (this._pauseTime ?? t));
94
+ const t1 = this._t1 + (t - (this._pauseTime ?? t));
95
+ const ct = this.clip.resolveClipTime(t, t0, this._rate >= 0 ? 0 : this.clip.length, this._rate, t1);
96
+ this.clip.streamTick(StreamState.Playing, ct, this._rate, true);
88
97
  this.state = StreamState.Playing;
89
98
  this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
90
99
  this._lastClipTime = undefined;
100
+ this._lastTickTime = undefined;
91
101
  if (this.layer.active !== this) {
92
102
  this.layer._activateLayerClip(this, opts);
93
103
  this.layer._evaulate();
@@ -118,9 +128,11 @@ export class LayerClip {
118
128
  if (this._loop)
119
129
  this._t1 = Infinity;
120
130
  this._lastClipTime = undefined;
131
+ this._lastTickTime = undefined;
121
132
  if (this.layer.active !== this && !opts?.dontActivateLayer) {
122
133
  this.layer._activateLayerClip(this, { fade: opts?.fade });
123
134
  }
135
+ this.clip.streamSeek(ct);
124
136
  this.layer._evaulate();
125
137
  }
126
138
  /** @internal */
@@ -159,14 +171,15 @@ export class LayerClip {
159
171
  this.state = entry.state;
160
172
  }
161
173
  get clipTime() {
162
- return this._lastClipTime !== undefined ? this._lastClipTime : this.defaultPlaySpeed > 0 ? 0 : this.clip.length;
174
+ return this._lastTickTime !== undefined ? this._lastTickTime : this.defaultPlaySpeed > 0 ? 0 : this.clip.length;
163
175
  }
164
176
  stop() {
165
177
  this._stopped = true;
166
178
  this._pauseTime = this._t0;
167
179
  this._lastClipTime = undefined;
180
+ this._lastTickTime = undefined;
168
181
  this._rate = 1;
169
- this.clip.streamStop();
182
+ this.clip.streamTick(StreamState.Ended, this._t0, 1, true);
170
183
  this.state = StreamState.Ended;
171
184
  this.animation._pendingEvents.push({ evt: AnimationEvents.onLayerClipState, args: [this] });
172
185
  }
@@ -8,6 +8,7 @@ export interface Stream {
8
8
  pause: () => void;
9
9
  seek: (t: number) => void;
10
10
  stop: () => void;
11
+ length?: () => number | undefined;
11
12
  }
12
13
  export interface PlayOptions {
13
14
  speed?: number;
@@ -1,6 +1,7 @@
1
1
  import { ClipTrackEntity } from '../../data';
2
2
  import { Clip } from '../clips/clip';
3
3
  import { Keyframe } from '../keyframe';
4
+ import { StreamState } from '../stream';
4
5
  import { Track } from './track';
5
6
  export declare class ClipTrack extends Track {
6
7
  readonly clip: Clip;
@@ -23,4 +24,7 @@ export declare class ClipTrack extends Track {
23
24
  }): void;
24
25
  get sortedBlocks(): ClipTrackEntity[];
25
26
  computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
27
+ streamPause(): void;
28
+ streamSeek(t: number): void;
29
+ streamTick(clipState: StreamState, t: number, rate: number, force?: boolean, parentWeight?: number): void;
26
30
  }
@@ -65,4 +65,29 @@ export class ClipTrack extends Track {
65
65
  }
66
66
  return valueBefore;
67
67
  }
68
+ streamPause() {
69
+ this.clip.streamPause();
70
+ }
71
+ streamSeek(t) {
72
+ const blocks = this.sortedBlocks;
73
+ for (let i = blocks.length - 1; i >= 0; i--) {
74
+ const block = blocks[i];
75
+ if (block.t0 > t)
76
+ continue;
77
+ const ct = this.clip.resolveClipTime(t, block.t0, block.s0, block.rate, block.t1);
78
+ this.clip.streamSeek(ct);
79
+ return;
80
+ }
81
+ }
82
+ streamTick(clipState, t, rate, force = false, parentWeight) {
83
+ const blocks = this.sortedBlocks;
84
+ for (let i = blocks.length - 1; i >= 0; i--) {
85
+ const block = blocks[i];
86
+ if (block.t0 > t)
87
+ continue;
88
+ const ct = this.clip.resolveClipTime(t, block.t0, block.s0, block.rate, block.t1);
89
+ this.clip.streamTick(clipState, ct, block.rate, force);
90
+ return;
91
+ }
92
+ }
68
93
  }
@@ -0,0 +1,40 @@
1
+ import { StreamTrackEntity } from '../../data';
2
+ import { Entity } from '../../entity';
3
+ import { Animation } from '../animation';
4
+ import { Keyframe } from '../keyframe';
5
+ import { Stream, StreamState } from '../stream';
6
+ import { Track } from './track';
7
+ export declare class StreamTrack extends Track {
8
+ readonly animation: Animation;
9
+ private _entity;
10
+ private _property;
11
+ private _stream;
12
+ private _entities;
13
+ private _entitiesById;
14
+ private _entitiesDirty;
15
+ private _weights;
16
+ private _weightsById;
17
+ private _weightsDirty;
18
+ private _lastTick?;
19
+ private _lastLoopNumber?;
20
+ private _lastRate;
21
+ constructor(animation: Animation, _entity: Entity, _property: (string | number)[]);
22
+ get influencedPaths(): string[];
23
+ get stream(): Stream | undefined;
24
+ computePathProperty(t: number, p: string, valueBefore: any, parentWeight?: number): any;
25
+ setWeightsById(weights: {
26
+ [id: string]: Keyframe;
27
+ }): void;
28
+ get sortedWeights(): Keyframe[];
29
+ addBlock(k: StreamTrackEntity): void;
30
+ setBlocksById(weights: {
31
+ [id: string]: StreamTrackEntity;
32
+ }): void;
33
+ get sortedBlocks(): StreamTrackEntity[];
34
+ streamPause(): void;
35
+ streamSeek(t: number): void;
36
+ streamTick(clipState: StreamState, t: number, rate: number, force?: boolean, parentWeight?: number): void;
37
+ private _applyState;
38
+ private _resolveBlock;
39
+ private _resolveBlockTime;
40
+ }
@@ -0,0 +1,144 @@
1
+ import { StreamState } from '../stream';
2
+ import { resolveKeyframes, resolveKeyframeValue, Track } from './track';
3
+ export class StreamTrack extends Track {
4
+ constructor(animation, _entity, _property) {
5
+ super(animation);
6
+ this.animation = animation;
7
+ this._entity = _entity;
8
+ this._property = _property;
9
+ this._entities = [];
10
+ this._entitiesById = {};
11
+ this._entitiesDirty = false;
12
+ this._weights = [];
13
+ this._weightsById = {};
14
+ this._weightsDirty = false;
15
+ this._lastRate = 1;
16
+ }
17
+ get influencedPaths() {
18
+ return [];
19
+ }
20
+ get stream() {
21
+ if (!this._stream) {
22
+ let obj = this._entity;
23
+ for (let i = 0; i < this._property.length; i++) {
24
+ obj = obj[this._property[i]];
25
+ if (!obj)
26
+ return undefined;
27
+ }
28
+ this._stream = obj;
29
+ }
30
+ return this._stream;
31
+ }
32
+ computePathProperty(t, p, valueBefore, parentWeight) {
33
+ // n/a
34
+ }
35
+ setWeightsById(weights) {
36
+ this._weightsById = weights;
37
+ this._weightsDirty = true;
38
+ }
39
+ get sortedWeights() {
40
+ if (!this._weightsDirty)
41
+ return this._weights;
42
+ this._weights = Object.values(this._weightsById);
43
+ this._weights.sort((a, b) => a.t - b.t);
44
+ this._weightsDirty = false;
45
+ return this._weights;
46
+ }
47
+ addBlock(k) {
48
+ this._entitiesById[k.id] = k;
49
+ this._entitiesDirty = true;
50
+ }
51
+ setBlocksById(weights) {
52
+ this._entitiesById = weights;
53
+ this._entitiesDirty = true;
54
+ }
55
+ get sortedBlocks() {
56
+ if (!this._entitiesDirty)
57
+ return this._entities;
58
+ this._entities = Object.values(this._entitiesById);
59
+ this._entities.sort((a, b) => a.t0 - b.t0);
60
+ this._entitiesDirty = false;
61
+ return this._entities;
62
+ }
63
+ streamPause() {
64
+ this.stream?.pause();
65
+ }
66
+ streamSeek(t) {
67
+ const blockNow = this._resolveBlock(t);
68
+ if (!blockNow)
69
+ return;
70
+ const [bt, loopNumber] = this._resolveBlockTime(t, blockNow.t0, blockNow.s0, blockNow.rate, blockNow.t1);
71
+ this.stream?.seek(bt);
72
+ this._lastLoopNumber = loopNumber;
73
+ }
74
+ streamTick(clipState, t, rate, force = false, parentWeight) {
75
+ let weight = 1;
76
+ const [weightBefore, weightAfter] = resolveKeyframes(this.sortedWeights, t);
77
+ if (weightBefore)
78
+ weight = resolveKeyframeValue(t, weightBefore, weightAfter);
79
+ weight *= parentWeight ?? 1;
80
+ const blockBefore = this._lastTick === undefined ? undefined : this._resolveBlock(this._lastTick);
81
+ this._lastTick = t;
82
+ const blockNow = this._resolveBlock(t);
83
+ if (blockBefore !== blockNow || force) {
84
+ let desiredState = clipState;
85
+ if (!blockNow)
86
+ desiredState = StreamState.Paused;
87
+ else {
88
+ const [bt, loopNumber] = this._resolveBlockTime(t, blockNow.t0, blockNow.s0, blockNow.rate, blockNow.t1);
89
+ this._lastLoopNumber = loopNumber;
90
+ this.stream?.seek(bt);
91
+ }
92
+ this._applyState(desiredState, (blockNow?.rate ?? 1) * rate);
93
+ }
94
+ if (blockNow) {
95
+ const [bt, loopNumber] = this._resolveBlockTime(t, blockNow.t0, blockNow.s0, blockNow.rate, blockNow.t1);
96
+ if (loopNumber !== this._lastLoopNumber) {
97
+ console.log('Loop number changed', loopNumber, 'last', this._lastLoopNumber, 'seek', bt);
98
+ this._lastLoopNumber = loopNumber;
99
+ this.stream?.seek(bt);
100
+ }
101
+ }
102
+ }
103
+ _applyState(s, rate) {
104
+ switch (s) {
105
+ case StreamState.Playing:
106
+ this.stream?.play({ speed: rate });
107
+ break;
108
+ case StreamState.Paused:
109
+ this.stream?.pause();
110
+ break;
111
+ case StreamState.Ended:
112
+ this.stream?.stop();
113
+ break;
114
+ }
115
+ }
116
+ _resolveBlock(t) {
117
+ const blocks = this.sortedBlocks;
118
+ for (let i = blocks.length - 1; i >= 0; i--) {
119
+ const block = blocks[i];
120
+ if (block.t0 > t)
121
+ continue;
122
+ if (block.t1 !== undefined && block.t1 <= t)
123
+ return undefined;
124
+ return block;
125
+ }
126
+ return undefined;
127
+ }
128
+ _resolveBlockTime(t, t0, s0, rate, t1 = Infinity) {
129
+ const length = this.stream?.length?.() ?? Infinity;
130
+ if (length === 0)
131
+ return [0, 0];
132
+ t = Math.min(t, t1);
133
+ const ct = s0 + (t - t0) * rate;
134
+ const loopNumber = Math.floor(ct / length);
135
+ let bounded = ct % length;
136
+ if (bounded < 0)
137
+ bounded += length;
138
+ if (bounded === 0 && rate >= +0 && t === t1)
139
+ bounded += length;
140
+ if (bounded === 0 && rate < 0 && t === t0)
141
+ bounded += length;
142
+ return [bounded, loopNumber];
143
+ }
144
+ }
@@ -0,0 +1,48 @@
1
+ import { ActionBehavior, ActionBehaviorConstructorProps } from "../actionbehavior";
2
+ import { Component } from "../component";
3
+ import { ContextManager } from "../context";
4
+ /**
5
+ * @zbehavior
6
+ * @zicon play_circle
7
+ * @zgroup Animation Actions
8
+ */
9
+ export declare class ActivateState extends ActionBehavior {
10
+ private zcomponent;
11
+ /**
12
+ * @zprop
13
+ * @zgroup Activate State Settings
14
+ * @zgrouppriority 20
15
+ * @zvalues layerclipids
16
+ */
17
+ state: string | undefined;
18
+ /**
19
+ * @zprop
20
+ * @zgroup Override Fade
21
+ * @zgrouppriority 10
22
+ */
23
+ fadeTime?: number;
24
+ /**
25
+ * @zprop
26
+ * @zgroup Override Fade
27
+ * @zgrouppriority 10
28
+ * @zdefault 0
29
+ */
30
+ pin?: Pin | number;
31
+ /**
32
+ * @zprop
33
+ * @zgroup Override Fade
34
+ * @zgrouppriority 10
35
+ * @zdefault 0
36
+ * @zvalues easings
37
+ */
38
+ easing?: string;
39
+ constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
40
+ perform(): void;
41
+ /** @zprop */
42
+ preview(): void;
43
+ }
44
+ export declare enum Pin {
45
+ Start = 0,
46
+ Middle = 0.5,
47
+ End = 1
48
+ }
@@ -0,0 +1,39 @@
1
+ import { ActionBehavior, } from "../actionbehavior";
2
+ import { registerBehaviorRunAtDesignTime } from "../behavior";
3
+ /**
4
+ * @zbehavior
5
+ * @zicon play_circle
6
+ * @zgroup Animation Actions
7
+ */
8
+ export class ActivateState extends ActionBehavior {
9
+ constructor(contextManager, instance, props) {
10
+ super(contextManager, instance, props);
11
+ this.zcomponent = this.getZComponentInstance();
12
+ }
13
+ perform() {
14
+ if (!this.state)
15
+ return;
16
+ const layerclip = this.zcomponent.animation.layerClipByID.get(this.state);
17
+ if (!layerclip)
18
+ return;
19
+ const opts = {
20
+ fade: {
21
+ time: this.fadeTime,
22
+ pin: this.pin,
23
+ easing: this.easing
24
+ }
25
+ };
26
+ layerclip.play(opts);
27
+ }
28
+ /** @zprop */
29
+ preview() {
30
+ this.perform();
31
+ }
32
+ }
33
+ export var Pin;
34
+ (function (Pin) {
35
+ Pin[Pin["Start"] = 0] = "Start";
36
+ Pin[Pin["Middle"] = 0.5] = "Middle";
37
+ Pin[Pin["End"] = 1] = "End";
38
+ })(Pin || (Pin = {}));
39
+ registerBehaviorRunAtDesignTime(ActivateState);
@@ -0,0 +1,22 @@
1
+ import { ActionBehavior, ActionBehaviorConstructorProps } from "../../actionbehavior";
2
+ import { Component } from "../../component";
3
+ import { ContextManager } from "../../context";
4
+ /**
5
+ * @zbehavior
6
+ * @zicon pause_circle
7
+ * @zgroup Stream Actions
8
+ */
9
+ export declare class PauseStream extends ActionBehavior {
10
+ private zcomponent;
11
+ /**
12
+ * @zprop
13
+ * @zgroup Pause Settings
14
+ * @zgrouppriority 20
15
+ * @zvalues streamids
16
+ */
17
+ stream: string | undefined;
18
+ constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
19
+ perform(): void;
20
+ /** @zprop */
21
+ preview(): void;
22
+ }
@@ -0,0 +1,26 @@
1
+ import { ActionBehavior, } from "../../actionbehavior";
2
+ import { registerBehaviorRunAtDesignTime } from "../../behavior";
3
+ /**
4
+ * @zbehavior
5
+ * @zicon pause_circle
6
+ * @zgroup Stream Actions
7
+ */
8
+ export class PauseStream extends ActionBehavior {
9
+ constructor(contextManager, instance, props) {
10
+ super(contextManager, instance, props);
11
+ this.zcomponent = this.getZComponentInstance();
12
+ }
13
+ perform() {
14
+ if (!this.stream)
15
+ return;
16
+ const stream = this.zcomponent.resolveStreamID(this.stream);
17
+ if (!stream)
18
+ return;
19
+ stream.pause();
20
+ }
21
+ /** @zprop */
22
+ preview() {
23
+ this.perform();
24
+ }
25
+ }
26
+ registerBehaviorRunAtDesignTime(PauseStream);
@@ -0,0 +1,45 @@
1
+ import { ActionBehavior, ActionBehaviorConstructorProps } from "../../actionbehavior";
2
+ import { Component } from "../../component";
3
+ import { ContextManager } from "../../context";
4
+ /**
5
+ * @zbehavior
6
+ * @zicon play_circle
7
+ * @zgroup Stream Actions
8
+ */
9
+ export declare class PlayStream extends ActionBehavior {
10
+ private zcomponent;
11
+ /**
12
+ * @zprop
13
+ * @zgroup Play Settings
14
+ * @zgrouppriority 20
15
+ * @zvalues streamids
16
+ */
17
+ stream: string | undefined;
18
+ /**
19
+ * @zprop
20
+ * @zgroup Play Settings
21
+ * @zgrouppriority 20
22
+ * @zdefault false
23
+ */
24
+ loop?: boolean;
25
+ /**
26
+ * @zprop
27
+ * @zgroup Play Settings
28
+ * @zgrouppriority 20
29
+ * @zdefault 1
30
+ */
31
+ speed?: number;
32
+ /**
33
+ * Seek the clip to the start before playing
34
+ *
35
+ * @zprop
36
+ * @zgroup Play Settings
37
+ * @zgrouppriority 20
38
+ * @zdefault false
39
+ */
40
+ fromStart: boolean;
41
+ constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
42
+ perform(): void;
43
+ /** @zprop */
44
+ preview(): void;
45
+ }
@@ -0,0 +1,37 @@
1
+ import { ActionBehavior, } from "../../actionbehavior";
2
+ import { registerBehaviorRunAtDesignTime } from "../../behavior";
3
+ /**
4
+ * @zbehavior
5
+ * @zicon play_circle
6
+ * @zgroup Stream Actions
7
+ */
8
+ export class PlayStream extends ActionBehavior {
9
+ constructor(contextManager, instance, props) {
10
+ super(contextManager, instance, props);
11
+ this.zcomponent = this.getZComponentInstance();
12
+ /**
13
+ * Seek the clip to the start before playing
14
+ *
15
+ * @zprop
16
+ * @zgroup Play Settings
17
+ * @zgrouppriority 20
18
+ * @zdefault false
19
+ */
20
+ this.fromStart = false;
21
+ }
22
+ perform() {
23
+ if (!this.stream)
24
+ return;
25
+ const stream = this.zcomponent.resolveStreamID(this.stream);
26
+ if (!stream)
27
+ return;
28
+ if (this.fromStart ?? false)
29
+ stream.seek(0);
30
+ stream.play({ loop: this.loop, speed: this.speed });
31
+ }
32
+ /** @zprop */
33
+ preview() {
34
+ this.perform();
35
+ }
36
+ }
37
+ registerBehaviorRunAtDesignTime(PlayStream);
@@ -0,0 +1,29 @@
1
+ import { ActionBehavior, ActionBehaviorConstructorProps } from "../../actionbehavior";
2
+ import { Component } from "../../component";
3
+ import { ContextManager } from "../../context";
4
+ /**
5
+ * @zbehavior
6
+ * @zicon fast_forward
7
+ * @zgroup Stream Actions
8
+ */
9
+ export declare class SeekStream extends ActionBehavior {
10
+ private zcomponent;
11
+ /**
12
+ * @zprop
13
+ * @zgroup Stop Settings
14
+ * @zgrouppriority 20
15
+ * @zvalues streamids
16
+ */
17
+ stream: string | undefined;
18
+ /**
19
+ * @zprop
20
+ * @zgroup Stop Settings
21
+ * @zgrouppriority 20
22
+ * @zdefault 0
23
+ */
24
+ time: number;
25
+ constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
26
+ perform(): void;
27
+ /** @zprop */
28
+ preview(): void;
29
+ }
@@ -0,0 +1,33 @@
1
+ import { ActionBehavior, } from "../../actionbehavior";
2
+ import { registerBehaviorRunAtDesignTime } from "../../behavior";
3
+ /**
4
+ * @zbehavior
5
+ * @zicon fast_forward
6
+ * @zgroup Stream Actions
7
+ */
8
+ export class SeekStream extends ActionBehavior {
9
+ constructor(contextManager, instance, props) {
10
+ super(contextManager, instance, props);
11
+ this.zcomponent = this.getZComponentInstance();
12
+ /**
13
+ * @zprop
14
+ * @zgroup Stop Settings
15
+ * @zgrouppriority 20
16
+ * @zdefault 0
17
+ */
18
+ this.time = 0;
19
+ }
20
+ perform() {
21
+ if (!this.stream)
22
+ return;
23
+ const stream = this.zcomponent.resolveStreamID(this.stream);
24
+ if (!stream)
25
+ return;
26
+ stream.seek(this.time ?? 0);
27
+ }
28
+ /** @zprop */
29
+ preview() {
30
+ this.perform();
31
+ }
32
+ }
33
+ registerBehaviorRunAtDesignTime(SeekStream);
@@ -0,0 +1,22 @@
1
+ import { ActionBehavior, ActionBehaviorConstructorProps } from "../../actionbehavior";
2
+ import { Component } from "../../component";
3
+ import { ContextManager } from "../../context";
4
+ /**
5
+ * @zbehavior
6
+ * @zicon stop_circle
7
+ * @zgroup Stream Actions
8
+ */
9
+ export declare class StopStream extends ActionBehavior {
10
+ private zcomponent;
11
+ /**
12
+ * @zprop
13
+ * @zgroup Stop Settings
14
+ * @zgrouppriority 20
15
+ * @zvalues streamids
16
+ */
17
+ stream: string | undefined;
18
+ constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
19
+ perform(): void;
20
+ /** @zprop */
21
+ preview(): void;
22
+ }
@@ -0,0 +1,26 @@
1
+ import { ActionBehavior, } from "../../actionbehavior";
2
+ import { registerBehaviorRunAtDesignTime } from "../../behavior";
3
+ /**
4
+ * @zbehavior
5
+ * @zicon stop_circle
6
+ * @zgroup Stream Actions
7
+ */
8
+ export class StopStream extends ActionBehavior {
9
+ constructor(contextManager, instance, props) {
10
+ super(contextManager, instance, props);
11
+ this.zcomponent = this.getZComponentInstance();
12
+ }
13
+ perform() {
14
+ if (!this.stream)
15
+ return;
16
+ const stream = this.zcomponent.resolveStreamID(this.stream);
17
+ if (!stream)
18
+ return;
19
+ stream.stop();
20
+ }
21
+ /** @zprop */
22
+ preview() {
23
+ this.perform();
24
+ }
25
+ }
26
+ registerBehaviorRunAtDesignTime(StopStream);
@@ -119,12 +119,15 @@ export interface ClipTrackEntity {
119
119
  }
120
120
  export interface StreamTrack extends BaseTrack {
121
121
  type: TrackType.Stream;
122
+ name: string;
122
123
  data: ByID<StreamTrackEntity>;
123
124
  weight: ByID<Keyframe>;
125
+ property: (string | number)[];
124
126
  }
125
- export interface StreamTrackEntity extends BaseTrack {
127
+ export interface StreamTrackEntity {
128
+ id: string;
126
129
  t0: number;
127
- t1: number;
130
+ t1?: number;
128
131
  s0: number;
129
132
  rate: number;
130
133
  }
@@ -134,7 +137,8 @@ export interface FunctionTrack extends BaseTrack {
134
137
  }
135
138
  export type FunctionTrackEntity = EntityFunctionTrackEntity | ImportFunctionTrackEntity;
136
139
  export interface BaseFunctionTrackEntity {
137
- order: string;
140
+ id: string;
141
+ t0: number;
138
142
  type: 'entity' | 'import';
139
143
  args: ByID<any>;
140
144
  }
@@ -368,9 +368,20 @@ export function forEachNodeAncestor(zcomp, id, fn) {
368
368
  fn(node.parent.id);
369
369
  forEachNodeAncestor(zcomp, node.parent.id, fn);
370
370
  }
371
+ const lastNumberRegex = new RegExp(/[0-9]*$/);
371
372
  export function getUniqueLabel(zcomp, label) {
373
+ lastNumberRegex.lastIndex = 0;
374
+ let startIndex = 1;
375
+ const result = lastNumberRegex.exec(label);
376
+ if (result && result.length === 1) {
377
+ const num = parseInt(result[0]);
378
+ if (!isNaN(num)) {
379
+ startIndex = num + 1;
380
+ label = label.substring(0, result.index);
381
+ }
382
+ }
372
383
  const existingLabels = zcomp.entitiesByLabel ?? {};
373
- for (let i = 1; i < 10000; i++) {
384
+ for (let i = startIndex; i < 10000; i++) {
374
385
  const testName = i === 1 ? label : `${label} ${i.toString()}`;
375
386
  if (!Object.prototype.hasOwnProperty.call(existingLabels, testName)) {
376
387
  label = testName;
package/lib/inflate.js CHANGED
@@ -5,6 +5,7 @@ import { LayerClip } from './animation/layerclip';
5
5
  import { Layer } from './animation/layer';
6
6
  import { ClipTrack } from './animation/tracks/cliptrack';
7
7
  import { Bezier } from './animation/bezier';
8
+ import { StreamTrack } from './animation/tracks/streamtrack';
8
9
  export function createTrackFromData(zcomp, anim, data) {
9
10
  switch (data.type) {
10
11
  case Data.TrackType.Property: {
@@ -27,6 +28,15 @@ export function createTrackFromData(zcomp, anim, data) {
27
28
  ret.setWeightsById(processKeyframes(data.weight, anim.curves));
28
29
  return ret;
29
30
  }
31
+ case Data.TrackType.Stream: {
32
+ const entity = zcomp.entityByID.get(data.entityID);
33
+ if (!entity)
34
+ return;
35
+ const ret = new StreamTrack(anim, entity, data.property);
36
+ ret.setBlocksById(data.data);
37
+ ret.setWeightsById(processKeyframes(data.weight, anim.curves));
38
+ return ret;
39
+ }
30
40
  }
31
41
  return undefined;
32
42
  }
@@ -84,7 +94,7 @@ export function createClipFromData(zcomp, anim, data) {
84
94
  if (!keyframe)
85
95
  continue;
86
96
  length = Math.max(length, keyframe.t0);
87
- length = Math.max(length, keyframe.t1);
97
+ length = Math.max(length, keyframe.t1 ?? length);
88
98
  }
89
99
  break;
90
100
  case Data.TrackType.Stream:
@@ -92,7 +102,8 @@ export function createClipFromData(zcomp, anim, data) {
92
102
  if (!keyframe)
93
103
  continue;
94
104
  length = Math.max(length, keyframe.t0);
95
- length = Math.max(length, keyframe.t1);
105
+ if (keyframe.t1)
106
+ length = Math.max(length, keyframe.t1);
96
107
  }
97
108
  break;
98
109
  }
package/lib/types.d.ts CHANGED
@@ -71,10 +71,15 @@ export type Type = StringPrimitiveType | NumberPrimitiveType | BooleanPrimitiveT
71
71
  export declare enum TypeHint {
72
72
  'proportion' = "proportion",
73
73
  'color-norm-rgb' = "color-norm-rgb",
74
+ 'color-norm-rgba' = "color-norm-rgba",
74
75
  'color-unnorm-rgb' = "color-unnorm-rgb",
76
+ 'color-unnorm-rgba' = "color-unnorm-rgba",
75
77
  'color-hex' = "color-hex",
78
+ 'color-hexa' = "color-hexa",
76
79
  'color-css' = "color-css",
77
- 'text-multiline' = "text-multiline"
80
+ 'text-multiline' = "text-multiline",
81
+ 'angle-degrees' = "angle-degrees",
82
+ 'angle-radians' = "angle-radians"
78
83
  }
79
84
  export declare enum ValuesType {
80
85
  'files' = "files",
@@ -86,7 +91,8 @@ export declare enum ValuesType {
86
91
  'nodeids' = "nodeids",
87
92
  'layerclipids' = "layerclipids",
88
93
  'easings' = "easings",
89
- 'layerids' = "layerids"
94
+ 'layerids' = "layerids",
95
+ 'streamids' = "streamids"
90
96
  }
91
97
  export interface Values {
92
98
  type: ValuesType;
@@ -129,6 +135,10 @@ export interface ComponentInfo {
129
135
  allowedChildren: string[];
130
136
  allowedParents?: string[];
131
137
  defaultChildren?: DefaultChild[];
138
+ streams: StreamInfo[];
139
+ streamsObjects: {
140
+ [id: string]: string;
141
+ };
132
142
  }
133
143
  export interface ValueInfo {
134
144
  name: string;
@@ -144,6 +154,9 @@ export interface PreviewInfo {
144
154
  comments?: string[];
145
155
  filePattern: string;
146
156
  }
157
+ export interface StreamInfo {
158
+ property: (string | number)[];
159
+ }
147
160
  export interface SourceFileTypeInfo {
148
161
  components: {
149
162
  [id: string]: ComponentInfo;
package/lib/types.js CHANGED
@@ -19,10 +19,15 @@ export var TypeHint;
19
19
  (function (TypeHint) {
20
20
  TypeHint["proportion"] = "proportion";
21
21
  TypeHint["color-norm-rgb"] = "color-norm-rgb";
22
+ TypeHint["color-norm-rgba"] = "color-norm-rgba";
22
23
  TypeHint["color-unnorm-rgb"] = "color-unnorm-rgb";
24
+ TypeHint["color-unnorm-rgba"] = "color-unnorm-rgba";
23
25
  TypeHint["color-hex"] = "color-hex";
26
+ TypeHint["color-hexa"] = "color-hexa";
24
27
  TypeHint["color-css"] = "color-css";
25
28
  TypeHint["text-multiline"] = "text-multiline";
29
+ TypeHint["angle-degrees"] = "angle-degrees";
30
+ TypeHint["angle-radians"] = "angle-radians";
26
31
  })(TypeHint || (TypeHint = {}));
27
32
  export var ValuesType;
28
33
  (function (ValuesType) {
@@ -36,6 +41,7 @@ export var ValuesType;
36
41
  ValuesType["layerclipids"] = "layerclipids";
37
42
  ValuesType["easings"] = "easings";
38
43
  ValuesType["layerids"] = "layerids";
44
+ ValuesType["streamids"] = "streamids";
39
45
  })(ValuesType || (ValuesType = {}));
40
46
  function valuesCompatible(l, r) {
41
47
  if (!l && !r)
@@ -1,4 +1,4 @@
1
- import { Animation } from './animation/index';
1
+ import { Animation, Stream } from './animation/index';
2
2
  import { Component, ComponentChildren, ConstructorForComponent, ConstructorProps } from './component';
3
3
  import { ContextManager, Context } from './context';
4
4
  import { Entity } from './entity';
@@ -44,6 +44,12 @@ export declare class ZComponent<RootType = any> extends Component<RootType> {
44
44
  constructed: Promise<void>;
45
45
  isConstructed: boolean;
46
46
  animation: Animation;
47
+ /**
48
+ * @zstreams layerclipids
49
+ */
50
+ streams: {
51
+ [id: string]: Stream;
52
+ };
47
53
  private _nodesById;
48
54
  private _behaviorsToInitialize;
49
55
  private _constructorPropOverridesByEntityID;
@@ -63,5 +69,6 @@ export declare class ZComponent<RootType = any> extends Component<RootType> {
63
69
  private _setEntityProp;
64
70
  private _setEntityPropPath;
65
71
  _getNodeById(id: string): Component | undefined;
72
+ resolveStreamID(id: string): Stream | undefined;
66
73
  dispose(): never;
67
74
  }
package/lib/zcomponent.js CHANGED
@@ -31,6 +31,10 @@ export class ZComponent extends Component {
31
31
  this.constructed = new Promise(resolve => this._constructedResolve = resolve);
32
32
  this.isConstructed = false;
33
33
  this.animation = new Animation(false);
34
+ /**
35
+ * @zstreams layerclipids
36
+ */
37
+ this.streams = {};
34
38
  this._nodesById = new Map();
35
39
  this._behaviorsToInitialize = [];
36
40
  this._constructorPropOverridesByEntityID = new Map();
@@ -60,6 +64,10 @@ export class ZComponent extends Component {
60
64
  if (this._opts.data.animation)
61
65
  populateAnimationTracksFromData(this, this.animation, this._opts.data.animation);
62
66
  this.animation.initialize();
67
+ for (const layerClip of this.animation.layerClipByID.values()) {
68
+ if (layerClip.id)
69
+ this.streams[layerClip.id] = layerClip;
70
+ }
63
71
  this.isConstructed = true;
64
72
  this._constructedResolve();
65
73
  started(contextManager).then(() => {
@@ -104,6 +112,8 @@ export class ZComponent extends Component {
104
112
  if (node?.label) {
105
113
  that.entityByLabel.set(node.label, this);
106
114
  that.nodeByLabel.set(node.label, this);
115
+ if (this.element)
116
+ this.element['__zlabel'] = node.label;
107
117
  }
108
118
  that._nodesById.set(nodeId, this);
109
119
  for (const element of this.elementsResolved) {
@@ -370,6 +380,18 @@ export class ZComponent extends Component {
370
380
  _getNodeById(id) {
371
381
  return this._nodesById.get(id);
372
382
  }
383
+ resolveStreamID(id) {
384
+ const parts = id.split('.');
385
+ let obj = this.entityByID.get(parts[0]);
386
+ if (!obj)
387
+ return undefined;
388
+ for (let i = 1; i < parts.length; i++) {
389
+ if (!obj)
390
+ return undefined;
391
+ obj = obj[parts[i]];
392
+ }
393
+ return obj;
394
+ }
373
395
  dispose() {
374
396
  this.animation.dispose();
375
397
  for (const entity of this.entityByID.values()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zcomponent/core",
3
- "version": "1.0.0",
3
+ "version": "1.2.0-beta",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",