@xtia/timeline 1.0.5 → 1.0.7
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 +410 -6
- package/index.js +8 -1
- package/internal/emitters.d.ts +55 -29
- package/internal/emitters.js +241 -106
- package/internal/point.d.ts +15 -6
- package/internal/point.js +43 -0
- package/internal/range.d.ts +14 -4
- package/internal/range.js +98 -0
- package/internal/timeline.d.ts +3 -3
- package/internal/timeline.js +7 -66
- package/package.json +1 -1
package/internal/emitters.js
CHANGED
|
@@ -1,119 +1,254 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.createProgressEmitter = createProgressEmitter;
|
|
3
|
+
exports.RangeProgression = exports.Emitter = void 0;
|
|
5
4
|
const easing_1 = require("./easing");
|
|
6
5
|
const tween_1 = require("./tween");
|
|
7
6
|
const utils_1 = require("./utils");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
class Emitter {
|
|
8
|
+
constructor(onListen) {
|
|
9
|
+
this.onListen = onListen;
|
|
10
|
+
/**
|
|
11
|
+
* Used by tap() to create a clone of an Emitter with a redirected onListen
|
|
12
|
+
* Should be overridden in all Emitter subclasses
|
|
13
|
+
* @see {@link TimelineRange.redirect}
|
|
14
|
+
* @param listen
|
|
15
|
+
* @returns {this}
|
|
16
|
+
*/
|
|
17
|
+
this.redirect = (listen) => new Emitter(listen);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Registers a function to receive emitted values
|
|
21
|
+
* @param handler
|
|
22
|
+
* @returns A function to deregister the handler
|
|
23
|
+
*/
|
|
24
|
+
listen(handler) {
|
|
25
|
+
return this.onListen((value) => {
|
|
11
26
|
handler(value);
|
|
12
|
-
})
|
|
13
|
-
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a chainable emitter that applies arbitrary transformation to values emitted by its parent
|
|
31
|
+
* @param mapFunc
|
|
32
|
+
* @returns Listenable: emits transformed values
|
|
33
|
+
*/
|
|
34
|
+
map(mapFunc) {
|
|
35
|
+
return new Emitter(handler => this.onListen((value) => {
|
|
14
36
|
handler(mapFunc(value));
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a chainable emitter that selectively forwards emissions along the chain
|
|
41
|
+
* @param check Function that takes an emitted value and returns true if the emission should be forwarded along the chain
|
|
42
|
+
* @returns Listenable: emits values that pass the filter
|
|
43
|
+
*/
|
|
44
|
+
filter(check) {
|
|
45
|
+
return new Emitter(handler => this.onListen((value) => {
|
|
46
|
+
if (check(value))
|
|
18
47
|
handler(value);
|
|
19
|
-
}))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a chainable emitter that discards emitted values that are the same as the last value emitted by the new emitter
|
|
52
|
+
* @param compare Optional function that takes the previous and next values and returns true if they should be considered equal
|
|
53
|
+
*
|
|
54
|
+
* If no `compare` function is provided, values will be compared via `===`
|
|
55
|
+
* @returns Listenable: emits non-repeating values
|
|
56
|
+
*/
|
|
57
|
+
dedupe(compare) {
|
|
58
|
+
let previous = null;
|
|
59
|
+
return new Emitter(handler => {
|
|
60
|
+
const filteredHandler = (value) => {
|
|
61
|
+
if (!previous || (compare
|
|
62
|
+
? !compare(previous.value, value)
|
|
63
|
+
: (previous.value !== value))) {
|
|
64
|
+
handler(value);
|
|
65
|
+
previous = { value };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
return this.onListen(filteredHandler);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a chainable emitter that mirrors emissions from the parent emitter, invoking the provided callback `cb` as a side effect for each emission.
|
|
73
|
+
*
|
|
74
|
+
* The callback `cb` is called exactly once per parent emission, regardless of how many listeners are attached to the returned emitter.
|
|
75
|
+
* All listeners attached to the returned emitter receive the same values as the parent emitter.
|
|
76
|
+
*
|
|
77
|
+
* *Note*, the side effect `cb` is only invoked when there is at least one listener attached to the returned emitter
|
|
78
|
+
*
|
|
79
|
+
* @param cb A function to be called as a side effect for each value emitted by the parent emitter.
|
|
80
|
+
* @returns A new emitter that forwards all values from the parent, invoking `cb` as a side effect.
|
|
81
|
+
*/
|
|
82
|
+
tap(cb) {
|
|
83
|
+
const listeners = [];
|
|
84
|
+
let parentUnsubscribe = null;
|
|
85
|
+
const tappedListen = (handler) => {
|
|
86
|
+
listeners.push(handler);
|
|
87
|
+
if (listeners.length === 1) {
|
|
88
|
+
parentUnsubscribe = this.onListen(value => {
|
|
89
|
+
cb(value);
|
|
90
|
+
listeners.slice().forEach(fn => fn(value));
|
|
91
|
+
});
|
|
61
92
|
}
|
|
62
|
-
return
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
93
|
+
return () => {
|
|
94
|
+
const idx = listeners.indexOf(handler);
|
|
95
|
+
listeners.splice(idx, 1);
|
|
96
|
+
if (listeners.length === 0 && parentUnsubscribe) {
|
|
97
|
+
parentUnsubscribe();
|
|
98
|
+
parentUnsubscribe = null;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
return this.redirect(tappedListen);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Immediately passes this emitter to a callback and returns this emitter
|
|
106
|
+
*
|
|
107
|
+
* Allows branching without breaking a composition chain
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* range
|
|
112
|
+
* .tween("0%", "100%")
|
|
113
|
+
* .fork(branch => {
|
|
114
|
+
* branch
|
|
115
|
+
* .map(s => `Loading: ${s}`)
|
|
116
|
+
* .listen(s => document.title = s)
|
|
117
|
+
* })
|
|
118
|
+
* .listen(v => progressBar.style.width = v);
|
|
119
|
+
* ```
|
|
120
|
+
* @param cb
|
|
121
|
+
*/
|
|
122
|
+
fork(cb) {
|
|
123
|
+
cb(this);
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.Emitter = Emitter;
|
|
128
|
+
class RangeProgression extends Emitter {
|
|
129
|
+
constructor() {
|
|
130
|
+
super(...arguments);
|
|
131
|
+
this.redirect = (listen) => new RangeProgression(listen);
|
|
132
|
+
}
|
|
133
|
+
ease(easer) {
|
|
134
|
+
if (!easer)
|
|
135
|
+
return this;
|
|
136
|
+
const easerFunc = typeof easer == "string"
|
|
137
|
+
? easing_1.easers[easer]
|
|
138
|
+
: easer;
|
|
139
|
+
return new RangeProgression(easer ? (handler => this.onListen((progress) => {
|
|
140
|
+
handler(easerFunc(progress));
|
|
141
|
+
})) : h => this.onListen(h));
|
|
142
|
+
}
|
|
143
|
+
tween(from, to) {
|
|
144
|
+
return new Emitter(handler => this.onListen(progress => handler((0, tween_1.tweenValue)(from, to, progress))));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Creates a chainable progress emitter that quantises progress, as emitted by its parent, to the nearest of `steps` discrete values.
|
|
148
|
+
*
|
|
149
|
+
* @param steps – positive integer (e.g. 10 → 0, .1, .2 … 1)
|
|
150
|
+
* @throws RangeError if steps is not a positive integer
|
|
151
|
+
* @returns Listenable: emits quantised progression values
|
|
152
|
+
*/
|
|
153
|
+
snap(steps) {
|
|
154
|
+
if (!Number.isInteger(steps) || steps <= 0) {
|
|
155
|
+
throw new RangeError('snap(steps) requires a positive integer');
|
|
156
|
+
}
|
|
157
|
+
return new RangeProgression(handler => this.onListen(progress => {
|
|
158
|
+
const snapped = Math.round(progress * steps) / steps;
|
|
159
|
+
handler((0, utils_1.clamp)(snapped, 0, 1));
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Creates a chainable progress emitter that emits `1` when the incoming progress value is greater‑than‑or‑equal to the supplied `threshold`, otherwise emits `0`
|
|
164
|
+
*
|
|
165
|
+
* @param threshold the cut‑off value
|
|
166
|
+
* @returns Listenable: emits 0 or 1 after comparing progress with a threshold
|
|
167
|
+
*/
|
|
168
|
+
threshold(threshold) {
|
|
169
|
+
return new RangeProgression(handler => this.onListen(progress => {
|
|
68
170
|
handler(progress >= threshold ? 1 : 0);
|
|
69
|
-
}))
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Creates a chainable progress emitter that clamps incoming values
|
|
175
|
+
* @param min default 0
|
|
176
|
+
* @param max default 1
|
|
177
|
+
* @returns Listenable: emits clamped progression values
|
|
178
|
+
*/
|
|
179
|
+
clamp(min = 0, max = 1) {
|
|
180
|
+
return new RangeProgression(handler => this.onListen(progress => handler((0, utils_1.clamp)(progress, min, max))));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Creates a chainable progress emitter that maps incoming values to a repeating linear scale
|
|
184
|
+
*
|
|
185
|
+
* ```plain
|
|
186
|
+
* count=2
|
|
187
|
+
* 1
|
|
188
|
+
* | / /
|
|
189
|
+
* o| / /
|
|
190
|
+
* u| / /
|
|
191
|
+
* t| / /
|
|
192
|
+
* | / /
|
|
193
|
+
* |/_____/_____
|
|
194
|
+
* 0 in 1
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @param count Number of repetitions
|
|
198
|
+
* @returns Listenable: emits scaled and repeating values
|
|
199
|
+
*/
|
|
200
|
+
repeat(count) {
|
|
201
|
+
count = Math.max(0, count);
|
|
202
|
+
return new RangeProgression(handler => this.onListen(progress => {
|
|
203
|
+
const out = (progress * count) % 1;
|
|
204
|
+
handler(out);
|
|
205
|
+
}));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Creates a chainable progress emitter that selectively forwards emissions along the chain
|
|
209
|
+
* @param check Function that takes an emitted value and returns true if the emission should be forwarded along the chain
|
|
210
|
+
* @returns Listenable: emits values that pass the filter
|
|
211
|
+
*/
|
|
212
|
+
filter(check) {
|
|
213
|
+
return new RangeProgression(handler => this.onListen((value) => {
|
|
214
|
+
if (check(value))
|
|
81
215
|
handler(value);
|
|
82
|
-
}))
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return Object.create(api ?? {}, propertyDescriptor);
|
|
97
|
-
}
|
|
98
|
-
function createTap(callback, create, parentListen) {
|
|
99
|
-
const listeners = [];
|
|
100
|
-
let parentUnsubscribe = null;
|
|
101
|
-
const tapOnListen = (handler) => {
|
|
102
|
-
listeners.push(handler);
|
|
103
|
-
if (listeners.length === 1) {
|
|
104
|
-
parentUnsubscribe = parentListen(value => {
|
|
105
|
-
callback(value);
|
|
106
|
-
listeners.slice().forEach(fn => fn(value));
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Creates a chainable progress emitter that discards emitted values that are the same as the last value emitted by the new emitter
|
|
220
|
+
* @returns Listenable: emits non-repeating values
|
|
221
|
+
*/
|
|
222
|
+
dedupe() {
|
|
223
|
+
let previous = null;
|
|
224
|
+
return new RangeProgression(handler => {
|
|
225
|
+
return this.onListen((value) => {
|
|
226
|
+
if (!previous === null || previous !== value) {
|
|
227
|
+
handler(value);
|
|
228
|
+
previous = value;
|
|
229
|
+
}
|
|
107
230
|
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Creates a chainable progress emitter that offsets its parent's values by the given delta, wrapping at 1
|
|
235
|
+
*
|
|
236
|
+
* ```plain
|
|
237
|
+
* 1
|
|
238
|
+
* | /
|
|
239
|
+
* o| /
|
|
240
|
+
* u|/ __ delta=.5
|
|
241
|
+
* t| /
|
|
242
|
+
* | /
|
|
243
|
+
* |___/__
|
|
244
|
+
* 0 in 1
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @param delta
|
|
248
|
+
* @returns Listenable: emits offset values
|
|
249
|
+
*/
|
|
250
|
+
offset(delta) {
|
|
251
|
+
return new RangeProgression(handler => this.onListen(value => handler((value + delta) % 1)));
|
|
252
|
+
}
|
|
119
253
|
}
|
|
254
|
+
exports.RangeProgression = RangeProgression;
|
package/internal/point.d.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { Emitter } from "./emitters";
|
|
1
|
+
import { Emitter, ListenFunc } from "./emitters";
|
|
2
2
|
import { TimelineRange } from "./range";
|
|
3
|
+
import { Timeline } from "./timeline";
|
|
3
4
|
export type PointEvent = {
|
|
4
5
|
direction: -1 | 1;
|
|
5
6
|
};
|
|
6
|
-
export
|
|
7
|
+
export declare class TimelinePoint extends Emitter<PointEvent> {
|
|
8
|
+
private timeline;
|
|
9
|
+
/**
|
|
10
|
+
* The point's absolute position on the Timeline
|
|
11
|
+
*/
|
|
12
|
+
readonly position: number;
|
|
13
|
+
/** @internal Manual construction of TimelinePoint is outside of the API contract and subject to undocumented change */
|
|
14
|
+
constructor(onListen: ListenFunc<PointEvent>, timeline: Timeline,
|
|
15
|
+
/**
|
|
16
|
+
* The point's absolute position on the Timeline
|
|
17
|
+
*/
|
|
18
|
+
position: number);
|
|
19
|
+
protected redirect: (listen: ListenFunc<PointEvent>) => TimelinePoint;
|
|
7
20
|
/**
|
|
8
21
|
* Creates a range on the Timeline, with a given duration, starting at this point
|
|
9
22
|
* @param duration
|
|
@@ -22,8 +35,4 @@ export interface TimelinePoint extends Emitter<PointEvent> {
|
|
|
22
35
|
* @returns Listenable: emits a PointEvent when the point is reached or passed by a Timeline seek
|
|
23
36
|
*/
|
|
24
37
|
delta(timeOffset: number): TimelinePoint;
|
|
25
|
-
/**
|
|
26
|
-
* The point's absolute position on the Timeline
|
|
27
|
-
*/
|
|
28
|
-
readonly position: number;
|
|
29
38
|
}
|
package/internal/point.js
CHANGED
|
@@ -1,2 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimelinePoint = void 0;
|
|
4
|
+
const emitters_1 = require("./emitters");
|
|
5
|
+
class TimelinePoint extends emitters_1.Emitter {
|
|
6
|
+
/** @internal Manual construction of TimelinePoint is outside of the API contract and subject to undocumented change */
|
|
7
|
+
constructor(onListen, timeline,
|
|
8
|
+
/**
|
|
9
|
+
* The point's absolute position on the Timeline
|
|
10
|
+
*/
|
|
11
|
+
position) {
|
|
12
|
+
super(onListen);
|
|
13
|
+
this.timeline = timeline;
|
|
14
|
+
this.position = position;
|
|
15
|
+
this.redirect = (listen) => new TimelinePoint(listen, this.timeline, this.position);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a range on the Timeline, with a given duration, starting at this point
|
|
19
|
+
* @param duration
|
|
20
|
+
* @returns Listenable: emits normalised (0..1) range progression
|
|
21
|
+
*/
|
|
22
|
+
range(duration) {
|
|
23
|
+
return this.timeline.range(this.position, duration);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a range on the Timeline, with a given end point, starting at this point
|
|
27
|
+
* @param endPoint
|
|
28
|
+
* @returns Listenable: emits normalised (0..1) range progression
|
|
29
|
+
*/
|
|
30
|
+
to(endPoint) {
|
|
31
|
+
const endPosition = typeof endPoint == "number"
|
|
32
|
+
? endPoint
|
|
33
|
+
: endPoint.position;
|
|
34
|
+
return this.timeline.range(this.position, endPosition - this.position);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a point on the Timeline at an offset position from this one
|
|
38
|
+
* @param timeOffset
|
|
39
|
+
* @returns Listenable: emits a PointEvent when the point is reached or passed by a Timeline seek
|
|
40
|
+
*/
|
|
41
|
+
delta(timeOffset) {
|
|
42
|
+
return this.timeline.point(this.position + timeOffset);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.TimelinePoint = TimelinePoint;
|
package/internal/range.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { Easer, easers } from "./easing";
|
|
2
|
-
import { RangeProgression } from "./emitters";
|
|
2
|
+
import { ListenFunc, RangeProgression } from "./emitters";
|
|
3
3
|
import { TimelinePoint } from "./point";
|
|
4
|
-
|
|
4
|
+
import { Timeline } from "./timeline";
|
|
5
|
+
export declare class TimelineRange extends RangeProgression {
|
|
6
|
+
private timeline;
|
|
7
|
+
private startPosition;
|
|
8
|
+
/** The duration of this range */
|
|
9
|
+
readonly duration: number;
|
|
10
|
+
private endPosition;
|
|
11
|
+
/** @internal Manual construction of RangeProgression is outside of the API contract and subject to undocumented change */
|
|
12
|
+
constructor(onListen: ListenFunc<number>, timeline: Timeline, startPosition: number,
|
|
13
|
+
/** The duration of this range */
|
|
14
|
+
duration: number);
|
|
15
|
+
protected redirect: (listen: ListenFunc<number>) => TimelineRange;
|
|
5
16
|
/**
|
|
6
17
|
* Creates two ranges by seperating one at a given point
|
|
7
18
|
* @param position Point of separation, relative to the range's start - if omitted, the range will be separated halfway
|
|
@@ -41,10 +52,9 @@ export interface TimelineRange extends RangeProgression {
|
|
|
41
52
|
* @returns true if the provided point is within the range
|
|
42
53
|
*/
|
|
43
54
|
contains(point: TimelinePoint): boolean;
|
|
55
|
+
contains(range: TimelineRange): boolean;
|
|
44
56
|
/** The point on the Timeline at which this range begins */
|
|
45
57
|
readonly start: TimelinePoint;
|
|
46
58
|
/** The point on the Timeline at which this range ends */
|
|
47
59
|
readonly end: TimelinePoint;
|
|
48
|
-
/** The duration of this range */
|
|
49
|
-
readonly duration: number;
|
|
50
60
|
}
|
package/internal/range.js
CHANGED
|
@@ -1,2 +1,100 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimelineRange = void 0;
|
|
4
|
+
const emitters_1 = require("./emitters");
|
|
5
|
+
const point_1 = require("./point");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
class TimelineRange extends emitters_1.RangeProgression {
|
|
8
|
+
/** @internal Manual construction of RangeProgression is outside of the API contract and subject to undocumented change */
|
|
9
|
+
constructor(onListen, timeline, startPosition,
|
|
10
|
+
/** The duration of this range */
|
|
11
|
+
duration) {
|
|
12
|
+
super(onListen);
|
|
13
|
+
this.timeline = timeline;
|
|
14
|
+
this.startPosition = startPosition;
|
|
15
|
+
this.duration = duration;
|
|
16
|
+
this.redirect = (listen) => new TimelineRange(listen, this.timeline, this.startPosition, this.duration);
|
|
17
|
+
this.start = timeline.point(startPosition);
|
|
18
|
+
this.end = timeline.point(startPosition + duration);
|
|
19
|
+
this.endPosition = startPosition + duration;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Creates two ranges by seperating one at a given point
|
|
23
|
+
* @param position Point of separation, relative to the range's start - if omitted, the range will be separated halfway
|
|
24
|
+
*
|
|
25
|
+
* Must be greater than 0 and less than the range's duration
|
|
26
|
+
* @returns Tuple of two ranges
|
|
27
|
+
*/
|
|
28
|
+
bisect(position = this.duration / 2) {
|
|
29
|
+
return [
|
|
30
|
+
this.timeline.range(position, this.startPosition),
|
|
31
|
+
this.timeline.range(position + this.startPosition, this.duration - this.startPosition),
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a series of evenly-spread points across the range, excluding the range's start and end
|
|
36
|
+
* @param count Number of Points to return
|
|
37
|
+
* @returns Array(count) of points
|
|
38
|
+
*/
|
|
39
|
+
spread(count) {
|
|
40
|
+
const delta = this.duration / (count + 1);
|
|
41
|
+
return [
|
|
42
|
+
...Array(count).fill(0).map((_, idx) => this.timeline.point(idx * delta + this.startPosition + delta))
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Progresses the Timeline across the range
|
|
47
|
+
* @param easer
|
|
48
|
+
*/
|
|
49
|
+
play(easer) {
|
|
50
|
+
this.timeline.pause();
|
|
51
|
+
this.timeline.currentTime = this.startPosition;
|
|
52
|
+
return this.timeline.seek(this.startPosition + this.duration, this.duration, easer);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new range representing a direct expansion of this one
|
|
56
|
+
* @param delta Amount to grow by (in time units)
|
|
57
|
+
* @param anchor Normalised position at which to expand (0 being the start, expanding right, 1 being the end, expanding left, 0.5 expanding evenly)
|
|
58
|
+
* @returns Listenable: this range will emit a progression value (0..1) when a `seek()` passes or intersects it
|
|
59
|
+
*/
|
|
60
|
+
grow(delta, anchor = 0) {
|
|
61
|
+
const clampedAnchor = (0, utils_1.clamp)(anchor, 0, 1);
|
|
62
|
+
const leftDelta = -delta * (1 - clampedAnchor);
|
|
63
|
+
const rightDelta = delta * clampedAnchor;
|
|
64
|
+
const newStart = this.startPosition + leftDelta;
|
|
65
|
+
const newEnd = this.startPosition + this.duration + rightDelta;
|
|
66
|
+
if (newEnd < newStart) {
|
|
67
|
+
const mid = (newStart + newEnd) / 2;
|
|
68
|
+
return this.timeline.range(mid, 0);
|
|
69
|
+
}
|
|
70
|
+
return this.timeline.range(newStart, newEnd - newStart);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new range representing a multiplicative expansion of this one
|
|
74
|
+
* @param factor Size multiplier
|
|
75
|
+
* @param anchor Normalised position at which to expand (0 being the start, expanding right, 1 being the end, expanding left, 0.5 expanding evenly)
|
|
76
|
+
* @returns Listenable: this range will emit a progression value (0..1) when a `seek()` passes or intersects it
|
|
77
|
+
*/
|
|
78
|
+
scale(factor, anchor = 0) {
|
|
79
|
+
if (factor <= 0) {
|
|
80
|
+
throw new RangeError('scale factor must be > 0');
|
|
81
|
+
}
|
|
82
|
+
const clampedAnchor = (0, utils_1.clamp)(anchor, 0, 1);
|
|
83
|
+
const oldLen = this.endPosition - this.startPosition;
|
|
84
|
+
const pivot = this.startPosition + oldLen * clampedAnchor;
|
|
85
|
+
const newStart = pivot - (pivot - this.startPosition) * factor;
|
|
86
|
+
const newEnd = pivot + (this.endPosition - pivot) * factor;
|
|
87
|
+
if (newEnd < newStart) {
|
|
88
|
+
const mid = (newStart + newEnd) / 2;
|
|
89
|
+
return this.timeline.range(mid, 0);
|
|
90
|
+
}
|
|
91
|
+
return this.timeline.range(newStart, newEnd - newStart);
|
|
92
|
+
}
|
|
93
|
+
contains(target) {
|
|
94
|
+
const [targetStart, targetEnd] = target instanceof point_1.TimelinePoint
|
|
95
|
+
? [target.position, target.position]
|
|
96
|
+
: [target.startPosition, target.startPosition + target.duration];
|
|
97
|
+
return targetStart >= this.startPosition && targetEnd < this.endPosition;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.TimelineRange = TimelineRange;
|
package/internal/timeline.d.ts
CHANGED
|
@@ -128,9 +128,9 @@ export declare class Timeline {
|
|
|
128
128
|
* @deprecated Use timeline.position += n
|
|
129
129
|
*/
|
|
130
130
|
step(delta: number): void;
|
|
131
|
-
tween<T extends Tweenable>(start: number | TimelinePoint, duration: number, apply: (v: Widen<T>) => void, from: T, to: T, easer?: Easer): ChainingInterface;
|
|
131
|
+
tween<T extends Tweenable>(start: number | TimelinePoint, duration: number, apply: (v: Widen<T>) => void, from: T, to: T, easer?: Easer | keyof typeof easers): ChainingInterface;
|
|
132
132
|
tween<T extends Tweenable>(start: number | TimelinePoint, end: TimelinePoint, // ease migration for tl.tween(0, tl.end, ...)
|
|
133
|
-
apply: (v: Widen<T>) => void, from: T, to: T, easer?: Easer): ChainingInterface;
|
|
133
|
+
apply: (v: Widen<T>) => void, from: T, to: T, easer?: Easer | keyof typeof easers): ChainingInterface;
|
|
134
134
|
at(position: number | TimelinePoint, action?: () => void, reverse?: boolean | (() => void)): ChainingInterface;
|
|
135
135
|
private createChainingInterface;
|
|
136
136
|
/**
|
|
@@ -139,7 +139,7 @@ export declare class Timeline {
|
|
|
139
139
|
get position(): number;
|
|
140
140
|
}
|
|
141
141
|
export interface ChainingInterface {
|
|
142
|
-
thenTween(duration: number, apply: (v:
|
|
142
|
+
thenTween<T extends Tweenable>(duration: number, apply: (v: Widen<T>) => void, from: T, to: T, easer: Easer): ChainingInterface;
|
|
143
143
|
then(action: () => void): ChainingInterface;
|
|
144
144
|
thenWait(duration: number): ChainingInterface;
|
|
145
145
|
readonly end: TimelinePoint;
|