@xtia/timeline 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/internal/point.d.ts +19 -2
- package/internal/point.js +28 -9
- package/internal/range.d.ts +1 -0
- package/internal/range.js +6 -24
- package/internal/timeline.d.ts +13 -3
- package/internal/timeline.js +26 -7
- package/package.json +1 -1
package/README.md
CHANGED
package/internal/point.d.ts
CHANGED
|
@@ -38,19 +38,31 @@ export declare class TimelinePoint extends Emitter<PointEvent> {
|
|
|
38
38
|
delta(timeOffset: number): TimelinePoint;
|
|
39
39
|
/**
|
|
40
40
|
* Seeks the parent Timeline to this point
|
|
41
|
+
* @deprecated Use timeline.seek(point)
|
|
41
42
|
*/
|
|
42
43
|
seek(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Smooth-seeks the parent Timeline to this point
|
|
46
|
+
* @deprecated Use timeline.seek(point)
|
|
47
|
+
*/
|
|
43
48
|
seek(duration: number, easer?: Easer): Promise<void>;
|
|
44
49
|
/**
|
|
45
50
|
* Creates an emitter that only emits on forward-moving seeks
|
|
46
|
-
* @returns
|
|
51
|
+
* @returns Listenable: emits forward-seeking point events
|
|
47
52
|
*/
|
|
48
53
|
forwardOnly(): Emitter<PointEvent>;
|
|
49
54
|
/**
|
|
50
55
|
* Creates an emitter that only emits on backward-moving seeks
|
|
51
|
-
* @returns
|
|
56
|
+
* @returns Listenable: emits backward-seeking point events
|
|
52
57
|
*/
|
|
53
58
|
reverseOnly(): Emitter<PointEvent>;
|
|
59
|
+
filter(check: (event: PointEvent) => boolean): Emitter<PointEvent>;
|
|
60
|
+
/**
|
|
61
|
+
* Creates an emitter that forwards events emitted by seeks of a specific direction
|
|
62
|
+
* @param allow Direction to allow
|
|
63
|
+
* @returns Listenable: emits point events that match the given direction
|
|
64
|
+
*/
|
|
65
|
+
filter(allow: -1 | 1): Emitter<PointEvent>;
|
|
54
66
|
/**
|
|
55
67
|
* Creates a Promise that will be resolved when the Timeline first seeks to/past this point
|
|
56
68
|
*
|
|
@@ -79,4 +91,9 @@ export declare class TimelinePoint extends Emitter<PointEvent> {
|
|
|
79
91
|
* @returns A function to deregister both handlers
|
|
80
92
|
*/
|
|
81
93
|
applyDirectional(apply: () => void, revert: () => void): UnsubscribeFunc;
|
|
94
|
+
/**
|
|
95
|
+
* Creates an emitter that forwards point events whose direction differs from the previous emission
|
|
96
|
+
* @returns Listenable: emits non-repeating point events
|
|
97
|
+
*/
|
|
98
|
+
dedupe(): Emitter<PointEvent>;
|
|
82
99
|
}
|
package/internal/point.js
CHANGED
|
@@ -43,24 +43,30 @@ export class TimelinePoint extends Emitter {
|
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* Creates an emitter that only emits on forward-moving seeks
|
|
46
|
-
* @returns
|
|
46
|
+
* @returns Listenable: emits forward-seeking point events
|
|
47
47
|
*/
|
|
48
48
|
forwardOnly() {
|
|
49
|
-
return
|
|
50
|
-
return this.onListen((ev) => {
|
|
51
|
-
if (ev.direction > 0)
|
|
52
|
-
handler(ev);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
49
|
+
return this.filter(1);
|
|
55
50
|
}
|
|
56
51
|
/**
|
|
57
52
|
* Creates an emitter that only emits on backward-moving seeks
|
|
58
|
-
* @returns
|
|
53
|
+
* @returns Listenable: emits backward-seeking point events
|
|
59
54
|
*/
|
|
60
55
|
reverseOnly() {
|
|
56
|
+
return this.filter(-1);
|
|
57
|
+
}
|
|
58
|
+
filter(arg) {
|
|
59
|
+
if (typeof arg == "number") {
|
|
60
|
+
return new Emitter(handler => {
|
|
61
|
+
return this.onListen((ev) => {
|
|
62
|
+
if (ev.direction === arg)
|
|
63
|
+
handler(ev);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
61
67
|
return new Emitter(handler => {
|
|
62
68
|
return this.onListen((ev) => {
|
|
63
|
-
if (ev
|
|
69
|
+
if (arg(ev))
|
|
64
70
|
handler(ev);
|
|
65
71
|
});
|
|
66
72
|
});
|
|
@@ -104,4 +110,17 @@ export class TimelinePoint extends Emitter {
|
|
|
104
110
|
? apply()
|
|
105
111
|
: revert());
|
|
106
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Creates an emitter that forwards point events whose direction differs from the previous emission
|
|
115
|
+
* @returns Listenable: emits non-repeating point events
|
|
116
|
+
*/
|
|
117
|
+
dedupe() {
|
|
118
|
+
let previous = 0;
|
|
119
|
+
return new Emitter(handler => this.onListen(event => {
|
|
120
|
+
if (event.direction !== previous) {
|
|
121
|
+
handler(event);
|
|
122
|
+
previous = event.direction;
|
|
123
|
+
}
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
107
126
|
}
|
package/internal/range.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export declare class TimelineRange extends RangeProgression {
|
|
|
48
48
|
* Progresses the Timeline across the range at 1000 units per second
|
|
49
49
|
* @param easer Optional easing function
|
|
50
50
|
* @returns Promise, resolved when the end is reached
|
|
51
|
+
* @deprecated Use timeline.play(range, easer?)
|
|
51
52
|
*/
|
|
52
53
|
play(easer?: Easer | keyof typeof easers): Promise<void>;
|
|
53
54
|
/**
|
package/internal/range.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { RangeProgression } from "./emitters";
|
|
2
2
|
import { TimelinePoint } from "./point";
|
|
3
|
-
import { clamp } from "./utils";
|
|
4
3
|
export class TimelineRange extends RangeProgression {
|
|
5
4
|
/** @internal Manual construction of RangeProgression is outside of the API contract and subject to undocumented change */
|
|
6
5
|
constructor(onListen, timeline, startPosition,
|
|
@@ -28,8 +27,8 @@ export class TimelineRange extends RangeProgression {
|
|
|
28
27
|
*/
|
|
29
28
|
bisect(position = this.duration / 2) {
|
|
30
29
|
return [
|
|
31
|
-
this.timeline.range(
|
|
32
|
-
this.timeline.range(position + this.startPosition, this.duration -
|
|
30
|
+
this.timeline.range(this.startPosition, position),
|
|
31
|
+
this.timeline.range(position + this.startPosition, this.duration - position),
|
|
33
32
|
];
|
|
34
33
|
}
|
|
35
34
|
/**
|
|
@@ -65,11 +64,12 @@ export class TimelineRange extends RangeProgression {
|
|
|
65
64
|
* Progresses the Timeline across the range at 1000 units per second
|
|
66
65
|
* @param easer Optional easing function
|
|
67
66
|
* @returns Promise, resolved when the end is reached
|
|
67
|
+
* @deprecated Use timeline.play(range, easer?)
|
|
68
68
|
*/
|
|
69
69
|
play(easer) {
|
|
70
70
|
this.timeline.pause();
|
|
71
71
|
this.timeline.currentTime = this.startPosition;
|
|
72
|
-
return this.timeline.seek(this.
|
|
72
|
+
return this.timeline.seek(this.end, this.duration, easer);
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Creates a new range representing a direct expansion of this one
|
|
@@ -78,16 +78,7 @@ export class TimelineRange extends RangeProgression {
|
|
|
78
78
|
* @returns Listenable: this range will emit a progression value (0..1) when a `seek()` passes or intersects it
|
|
79
79
|
*/
|
|
80
80
|
grow(delta, anchor = 0) {
|
|
81
|
-
|
|
82
|
-
const leftDelta = -delta * (1 - clampedAnchor);
|
|
83
|
-
const rightDelta = delta * clampedAnchor;
|
|
84
|
-
const newStart = this.startPosition + leftDelta;
|
|
85
|
-
const newEnd = this.startPosition + this.duration + rightDelta;
|
|
86
|
-
if (newEnd < newStart) {
|
|
87
|
-
const mid = (newStart + newEnd) / 2;
|
|
88
|
-
return this.timeline.range(mid, 0);
|
|
89
|
-
}
|
|
90
|
-
return this.timeline.range(newStart, newEnd - newStart);
|
|
81
|
+
return this.timeline.range(this.startPosition - (delta * anchor), this.duration + delta);
|
|
91
82
|
}
|
|
92
83
|
/**
|
|
93
84
|
* Creates a new range representing a multiplicative expansion of this one
|
|
@@ -99,16 +90,7 @@ export class TimelineRange extends RangeProgression {
|
|
|
99
90
|
if (factor <= 0) {
|
|
100
91
|
throw new RangeError('Scale factor must be > 0');
|
|
101
92
|
}
|
|
102
|
-
|
|
103
|
-
const oldLen = this.endPosition - this.startPosition;
|
|
104
|
-
const pivot = this.startPosition + oldLen * clampedAnchor;
|
|
105
|
-
const newStart = pivot - (pivot - this.startPosition) * factor;
|
|
106
|
-
const newEnd = pivot + (this.endPosition - pivot) * factor;
|
|
107
|
-
if (newEnd < newStart) {
|
|
108
|
-
const mid = (newStart + newEnd) / 2;
|
|
109
|
-
return this.timeline.range(mid, 0);
|
|
110
|
-
}
|
|
111
|
-
return this.timeline.range(newStart, newEnd - newStart);
|
|
93
|
+
return this.grow((factor - 1) * this.duration, anchor);
|
|
112
94
|
}
|
|
113
95
|
contains(target) {
|
|
114
96
|
const [targetStart, targetEnd] = target instanceof TimelinePoint
|
package/internal/timeline.d.ts
CHANGED
|
@@ -89,12 +89,12 @@ export declare class Timeline {
|
|
|
89
89
|
* Defines a range on this Timeline
|
|
90
90
|
*
|
|
91
91
|
* @param start The position on this Timeline at which the range starts
|
|
92
|
-
* @param duration Length of the resulting range
|
|
92
|
+
* @param duration Length of the resulting range
|
|
93
93
|
* @returns A range on the Timeline
|
|
94
94
|
*
|
|
95
95
|
* Listenable: this range will emit a progression value (0..1) when a `seek()` passes or intersects it
|
|
96
96
|
*/
|
|
97
|
-
range(start: number | TimelinePoint, duration
|
|
97
|
+
range(start: number | TimelinePoint, duration: number): TimelineRange;
|
|
98
98
|
/**
|
|
99
99
|
* Creates an observable range from position 0 to the Timeline's **current** final position
|
|
100
100
|
*/
|
|
@@ -124,6 +124,16 @@ export declare class Timeline {
|
|
|
124
124
|
*/
|
|
125
125
|
play(): void;
|
|
126
126
|
play(fps: number): void;
|
|
127
|
+
/**
|
|
128
|
+
* Performs a smooth-seek through a range at (1000 × this.timeScale) units per second
|
|
129
|
+
*/
|
|
130
|
+
play(range: TimelineRange, easer?: Easer): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Stops normal progression instigated by play()
|
|
133
|
+
*
|
|
134
|
+
* Does not affect ongoing smooth-seek operations or play(range)
|
|
135
|
+
*
|
|
136
|
+
*/
|
|
127
137
|
pause(): void;
|
|
128
138
|
/**
|
|
129
139
|
* Progresses the Timeline by 1 unit
|
|
@@ -148,7 +158,7 @@ export declare class Timeline {
|
|
|
148
158
|
get position(): number;
|
|
149
159
|
}
|
|
150
160
|
export interface ChainingInterface {
|
|
151
|
-
thenTween<T extends Tweenable>(duration: number, apply: (v: Widen<T>) => void, from: T, to: T, easer
|
|
161
|
+
thenTween<T extends Tweenable>(duration: number, apply: (v: Widen<T>) => void, from: T, to: T, easer?: Easer): ChainingInterface;
|
|
152
162
|
then(action: () => void): ChainingInterface;
|
|
153
163
|
thenWait(duration: number): ChainingInterface;
|
|
154
164
|
fork(fn: (chain: ChainingInterface) => void): ChainingInterface;
|
package/internal/timeline.js
CHANGED
|
@@ -179,12 +179,12 @@ export class Timeline {
|
|
|
179
179
|
? to
|
|
180
180
|
: to.position;
|
|
181
181
|
if (this.seeking) {
|
|
182
|
-
throw new Error("Can't seek while
|
|
182
|
+
throw new Error("Can't seek while a seek event is processed");
|
|
183
183
|
}
|
|
184
184
|
if (this.smoothSeeker !== null) {
|
|
185
185
|
this.smoothSeeker.pause();
|
|
186
186
|
// ensure any awaits are resolved for the previous seek
|
|
187
|
-
this.smoothSeeker.
|
|
187
|
+
this.smoothSeeker.seek(this.smoothSeeker.end);
|
|
188
188
|
this.smoothSeeker = null;
|
|
189
189
|
}
|
|
190
190
|
if (duration === 0) {
|
|
@@ -193,8 +193,12 @@ export class Timeline {
|
|
|
193
193
|
}
|
|
194
194
|
const seeker = new Timeline(true);
|
|
195
195
|
this.smoothSeeker = seeker;
|
|
196
|
-
seeker
|
|
197
|
-
|
|
196
|
+
seeker
|
|
197
|
+
.range(0, duration)
|
|
198
|
+
.ease(easer)
|
|
199
|
+
.tween(this.currentTime, toPosition)
|
|
200
|
+
.apply(v => this.seekDirect(v));
|
|
201
|
+
return seeker.end.promise();
|
|
198
202
|
}
|
|
199
203
|
seekDirect(toPosition) {
|
|
200
204
|
const fromPosition = this._currentTime;
|
|
@@ -252,7 +256,7 @@ export class Timeline {
|
|
|
252
256
|
range.handlers.slice().forEach(h => h(progress));
|
|
253
257
|
}
|
|
254
258
|
});
|
|
255
|
-
this.progressionHandlers.slice().forEach(h => h(
|
|
259
|
+
this.progressionHandlers.slice().forEach(h => h(toTime / this._endPosition));
|
|
256
260
|
}
|
|
257
261
|
sortEntries(direction) {
|
|
258
262
|
this.currentSortDirection = direction;
|
|
@@ -263,9 +267,18 @@ export class Timeline {
|
|
|
263
267
|
? sortTweens
|
|
264
268
|
: sortReverse);
|
|
265
269
|
}
|
|
266
|
-
play(
|
|
270
|
+
play(arg = default_fps, easer) {
|
|
267
271
|
if (this.interval !== null)
|
|
268
272
|
this.pause();
|
|
273
|
+
if (this.smoothSeeker) {
|
|
274
|
+
this.smoothSeeker.pause();
|
|
275
|
+
this.smoothSeeker.seek(this.smoothSeeker.end);
|
|
276
|
+
this.smoothSeeker = null;
|
|
277
|
+
}
|
|
278
|
+
if (arg instanceof TimelineRange) {
|
|
279
|
+
this.seek(arg.start);
|
|
280
|
+
return this.seek(arg.end, arg.duration / this.timeScale, easer);
|
|
281
|
+
}
|
|
269
282
|
let previousTime = Date.now();
|
|
270
283
|
this.interval = setInterval(() => {
|
|
271
284
|
const newTime = Date.now();
|
|
@@ -303,8 +316,14 @@ export class Timeline {
|
|
|
303
316
|
return;
|
|
304
317
|
}
|
|
305
318
|
this.currentTime += delta;
|
|
306
|
-
}, 1000 /
|
|
319
|
+
}, 1000 / arg);
|
|
307
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* Stops normal progression instigated by play()
|
|
323
|
+
*
|
|
324
|
+
* Does not affect ongoing smooth-seek operations or play(range)
|
|
325
|
+
*
|
|
326
|
+
*/
|
|
308
327
|
pause() {
|
|
309
328
|
if (this.interval === null)
|
|
310
329
|
return;
|