chnobli 0.1.8 → 0.1.9
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/package.json +9 -5
- package/src/animation/Animation.ts +2 -2
- package/src/animation/public.ts +39 -5
- package/src/chnobli.ts +15 -11
- package/src/property/Property.ts +2 -0
- package/src/property/StyleProperty.ts +2 -2
- package/src/scroll/Scroll.ts +172 -88
- package/src/scroll/index.ts +8 -0
- package/src/scroll/public.ts +23 -12
- package/src/stagger/stagger.ts +28 -14
- package/src/target/ObjectTarget.ts +124 -0
- package/src/target/Target.ts +13 -0
- package/src/tests/properties.test.ts +51 -1
- package/src/timeline/Nested.ts +1 -1
- package/src/timeline/{TimeLine.ts → Timeline.ts} +21 -1
- package/src/timeline/public.ts +168 -47
- package/src/timing/Timing.ts +37 -3
- package/src/utils/internal.ts +6 -3
- package/src/utils/utils.ts +16 -7
- package/src/values/StyleValue.ts +13 -1
- package/tsconfig.json +0 -1
- package/.editorconfig +0 -11
- package/.github/workflows/ci.yaml +0 -34
- package/.prettierignore +0 -4
- package/.prettierrc +0 -6
- package/.vscode/settings.json +0 -4
- package/LICENSE.md +0 -21
- package/README.md +0 -5
- package/auto-docs/easing.js.html +0 -342
- package/auto-docs/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-Bold-webfont.svg +0 -1830
- package/auto-docs/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/auto-docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
- package/auto-docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/auto-docs/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-Italic-webfont.svg +0 -1830
- package/auto-docs/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/auto-docs/fonts/OpenSans-Light-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-Light-webfont.svg +0 -1831
- package/auto-docs/fonts/OpenSans-Light-webfont.woff +0 -0
- package/auto-docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
- package/auto-docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/auto-docs/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/auto-docs/fonts/OpenSans-Regular-webfont.svg +0 -1831
- package/auto-docs/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/auto-docs/global.html +0 -4810
- package/auto-docs/index.html +0 -65
- package/auto-docs/scripts/linenumber.js +0 -25
- package/auto-docs/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/auto-docs/scripts/prettify/lang-css.js +0 -2
- package/auto-docs/scripts/prettify/prettify.js +0 -28
- package/auto-docs/styles/jsdoc-default.css +0 -358
- package/auto-docs/styles/prettify-jsdoc.css +0 -111
- package/auto-docs/styles/prettify-tomorrow.css +0 -132
- package/dist/animation/Animation.d.ts +0 -36
- package/dist/animation/Animation.d.ts.map +0 -1
- package/dist/animation/Animation.js +0 -230
- package/dist/animation/Animation.js.map +0 -1
- package/dist/animation/public.d.ts +0 -58
- package/dist/animation/public.d.ts.map +0 -1
- package/dist/animation/public.js +0 -107
- package/dist/animation/public.js.map +0 -1
- package/dist/chnobli.d.ts +0 -16
- package/dist/chnobli.d.ts.map +0 -1
- package/dist/chnobli.js +0 -63
- package/dist/chnobli.js.map +0 -1
- package/dist/property/BasicProperty.d.ts +0 -38
- package/dist/property/BasicProperty.d.ts.map +0 -1
- package/dist/property/BasicProperty.js +0 -72
- package/dist/property/BasicProperty.js.map +0 -1
- package/dist/property/ClassProperty.d.ts +0 -32
- package/dist/property/ClassProperty.d.ts.map +0 -1
- package/dist/property/ClassProperty.js +0 -108
- package/dist/property/ClassProperty.js.map +0 -1
- package/dist/property/Property.d.ts +0 -13
- package/dist/property/Property.d.ts.map +0 -1
- package/dist/property/Property.js +0 -20
- package/dist/property/Property.js.map +0 -1
- package/dist/property/StyleProperty.d.ts +0 -25
- package/dist/property/StyleProperty.d.ts.map +0 -1
- package/dist/property/StyleProperty.js +0 -221
- package/dist/property/StyleProperty.js.map +0 -1
- package/dist/property/TransformProperty.d.ts +0 -15
- package/dist/property/TransformProperty.d.ts.map +0 -1
- package/dist/property/TransformProperty.js +0 -43
- package/dist/property/TransformProperty.js.map +0 -1
- package/dist/property/TransformXYProperty.d.ts +0 -28
- package/dist/property/TransformXYProperty.d.ts.map +0 -1
- package/dist/property/TransformXYProperty.js +0 -65
- package/dist/property/TransformXYProperty.js.map +0 -1
- package/dist/responsive/ResponsiveEvent.d.ts +0 -17
- package/dist/responsive/ResponsiveEvent.d.ts.map +0 -1
- package/dist/responsive/ResponsiveEvent.js +0 -45
- package/dist/responsive/ResponsiveEvent.js.map +0 -1
- package/dist/responsive/TestEvent.d.ts +0 -11
- package/dist/responsive/TestEvent.d.ts.map +0 -1
- package/dist/responsive/TestEvent.js +0 -26
- package/dist/responsive/TestEvent.js.map +0 -1
- package/dist/scroll/Scroll.d.ts +0 -27
- package/dist/scroll/Scroll.d.ts.map +0 -1
- package/dist/scroll/Scroll.js +0 -132
- package/dist/scroll/Scroll.js.map +0 -1
- package/dist/scroll/ScrollEvent.d.ts +0 -17
- package/dist/scroll/ScrollEvent.d.ts.map +0 -1
- package/dist/scroll/ScrollEvent.js +0 -39
- package/dist/scroll/ScrollEvent.js.map +0 -1
- package/dist/scroll/public.d.ts +0 -7
- package/dist/scroll/public.d.ts.map +0 -1
- package/dist/scroll/public.js +0 -17
- package/dist/scroll/public.js.map +0 -1
- package/dist/stagger/stagger.d.ts +0 -19
- package/dist/stagger/stagger.d.ts.map +0 -1
- package/dist/stagger/stagger.js +0 -41
- package/dist/stagger/stagger.js.map +0 -1
- package/dist/target/BaseTarget.old.d.ts +0 -33
- package/dist/target/BaseTarget.old.d.ts.map +0 -1
- package/dist/target/BaseTarget.old.js +0 -73
- package/dist/target/BaseTarget.old.js.map +0 -1
- package/dist/target/DomTarget.d.ts +0 -41
- package/dist/target/DomTarget.d.ts.map +0 -1
- package/dist/target/DomTarget.js +0 -230
- package/dist/target/DomTarget.js.map +0 -1
- package/dist/target/Target.d.ts +0 -22
- package/dist/target/Target.d.ts.map +0 -1
- package/dist/target/Target.js +0 -21
- package/dist/target/Target.js.map +0 -1
- package/dist/target/TestDomNode.d.ts +0 -14
- package/dist/target/TestDomNode.d.ts.map +0 -1
- package/dist/target/TestDomNode.js +0 -55
- package/dist/target/TestDomNode.js.map +0 -1
- package/dist/timeline/Nested.d.ts +0 -30
- package/dist/timeline/Nested.d.ts.map +0 -1
- package/dist/timeline/Nested.js +0 -51
- package/dist/timeline/Nested.js.map +0 -1
- package/dist/timeline/TimeLine.d.ts +0 -32
- package/dist/timeline/TimeLine.d.ts.map +0 -1
- package/dist/timeline/TimeLine.js +0 -288
- package/dist/timeline/TimeLine.js.map +0 -1
- package/dist/timeline/public.d.ts +0 -135
- package/dist/timeline/public.d.ts.map +0 -1
- package/dist/timeline/public.js +0 -316
- package/dist/timeline/public.js.map +0 -1
- package/dist/timing/AnimationFrameTicker.d.ts +0 -32
- package/dist/timing/AnimationFrameTicker.d.ts.map +0 -1
- package/dist/timing/AnimationFrameTicker.js +0 -134
- package/dist/timing/AnimationFrameTicker.js.map +0 -1
- package/dist/timing/Ease.d.ts +0 -6
- package/dist/timing/Ease.d.ts.map +0 -1
- package/dist/timing/Ease.js +0 -15
- package/dist/timing/Ease.js.map +0 -1
- package/dist/timing/TestTicker.d.ts +0 -19
- package/dist/timing/TestTicker.d.ts.map +0 -1
- package/dist/timing/TestTicker.js +0 -81
- package/dist/timing/TestTicker.js.map +0 -1
- package/dist/timing/Ticker.d.ts +0 -14
- package/dist/timing/Ticker.d.ts.map +0 -1
- package/dist/timing/Ticker.js +0 -2
- package/dist/timing/Ticker.js.map +0 -1
- package/dist/timing/Timing.d.ts +0 -62
- package/dist/timing/Timing.d.ts.map +0 -1
- package/dist/timing/Timing.js +0 -257
- package/dist/timing/Timing.js.map +0 -1
- package/dist/timing/easing.d.ts +0 -158
- package/dist/timing/easing.d.ts.map +0 -1
- package/dist/timing/easing.js +0 -273
- package/dist/timing/easing.js.map +0 -1
- package/dist/utils/Events.d.ts +0 -9
- package/dist/utils/Events.d.ts.map +0 -1
- package/dist/utils/Events.js +0 -35
- package/dist/utils/Events.js.map +0 -1
- package/dist/utils/internal.d.ts +0 -2
- package/dist/utils/internal.d.ts.map +0 -1
- package/dist/utils/internal.js +0 -6
- package/dist/utils/internal.js.map +0 -1
- package/dist/utils/motionpath.d.ts +0 -16
- package/dist/utils/motionpath.d.ts.map +0 -1
- package/dist/utils/motionpath.js +0 -41
- package/dist/utils/motionpath.js.map +0 -1
- package/dist/utils/utils.d.ts +0 -43
- package/dist/utils/utils.d.ts.map +0 -1
- package/dist/utils/utils.js +0 -93
- package/dist/utils/utils.js.map +0 -1
- package/dist/values/ColorValue.d.ts +0 -12
- package/dist/values/ColorValue.d.ts.map +0 -1
- package/dist/values/ColorValue.js +0 -133
- package/dist/values/ColorValue.js.map +0 -1
- package/dist/values/StyleValue.d.ts +0 -40
- package/dist/values/StyleValue.d.ts.map +0 -1
- package/dist/values/StyleValue.js +0 -149
- package/dist/values/StyleValue.js.map +0 -1
- package/dist/values/Value.d.ts +0 -13
- package/dist/values/Value.d.ts.map +0 -1
- package/dist/values/Value.js +0 -38
- package/dist/values/Value.js.map +0 -1
- package/dist/values/defaultcolors.d.ts +0 -2
- package/dist/values/defaultcolors.d.ts.map +0 -1
- package/dist/values/defaultcolors.js +0 -149
- package/dist/values/defaultcolors.js.map +0 -1
- package/docs/INDEX.md +0 -15
- package/jsr.json +0 -9
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import StyleValue from '../values/StyleValue.js';
|
|
2
|
+
import Value from '../values/Value.js';
|
|
3
|
+
import { Target } from './Target.js';
|
|
4
|
+
|
|
5
|
+
export default class ObjectTarget implements Target {
|
|
6
|
+
private target: Record<string, any>;
|
|
7
|
+
|
|
8
|
+
// private _extFns: ExternalFunctions;
|
|
9
|
+
|
|
10
|
+
// private transformValues: Map<string, (Value | null)[]>;
|
|
11
|
+
private styleValues: Map<string, StyleValue | undefined>;
|
|
12
|
+
// private values: Map<string, Value>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* target a dom node or svg
|
|
16
|
+
*
|
|
17
|
+
* extFns: {getComputedStyle, getRootElement}
|
|
18
|
+
*/
|
|
19
|
+
constructor(target: Record<string, any>) {
|
|
20
|
+
this.target = target;
|
|
21
|
+
|
|
22
|
+
this.styleValues = new Map();
|
|
23
|
+
// this.values = new Map();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
inner() {
|
|
27
|
+
return this.target;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type() {
|
|
31
|
+
return 'object';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getValue(name: string): Value | null {
|
|
35
|
+
// return this.values.get(name) ?? null;
|
|
36
|
+
throw new Error('not supported');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setValue(name: string, value: Value) {
|
|
40
|
+
// this.values.set(name, value);
|
|
41
|
+
throw new Error('not supported');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
removeValue(name: string) {
|
|
45
|
+
// this.values.delete(name);
|
|
46
|
+
throw new Error('not supported');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getTransformValue(name: string): Value | null {
|
|
50
|
+
throw new Error('not supported');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setTransformValue(name: string, value: Value) {
|
|
54
|
+
throw new Error('not supported');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
removeTransformValue(name: string) {
|
|
58
|
+
throw new Error('not supported');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getStyleValue(name: string): StyleValue | null {
|
|
62
|
+
const v = this.styleValues.get(name) ?? null;
|
|
63
|
+
|
|
64
|
+
if (v !== null) return v;
|
|
65
|
+
|
|
66
|
+
const styleV = this.target[name];
|
|
67
|
+
if (typeof styleV === 'undefined' || styleV === null) {
|
|
68
|
+
return styleV;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const value = StyleValue.parse(styleV);
|
|
73
|
+
this.styleValues.set(name, value);
|
|
74
|
+
|
|
75
|
+
return value;
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.log('could not parse value', styleV);
|
|
78
|
+
return v;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
setStyleValue(name: string, value: StyleValue): void {
|
|
83
|
+
this.styleValues.set(name, value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
removeStyleValue(name: string): void {
|
|
87
|
+
this.styleValues.set(name, undefined);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
hasClass(name: string): boolean {
|
|
91
|
+
throw new Error('not supported');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
addClass(name: string): void {
|
|
95
|
+
throw new Error('not supported');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
removeClass(name: string): void {
|
|
99
|
+
throw new Error('not supported');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
unifyValues(name: string, a: Value, b: Value): [Value, Value] {
|
|
103
|
+
if (a.unit === b.unit) return [a, b];
|
|
104
|
+
|
|
105
|
+
if (!a.unit && b.unit) a.unit = b.unit;
|
|
106
|
+
|
|
107
|
+
if (!b.unit && a.unit) b.unit = a.unit;
|
|
108
|
+
|
|
109
|
+
return [a, b];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
apply() {
|
|
113
|
+
// style
|
|
114
|
+
for (const [k, v] of this.styleValues.entries()) {
|
|
115
|
+
if (v === undefined) {
|
|
116
|
+
console.log('delete', k);
|
|
117
|
+
delete this.target[k];
|
|
118
|
+
this.styleValues.delete(k);
|
|
119
|
+
} else {
|
|
120
|
+
this.target[k] = v.toMixed();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/target/Target.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import Value from '../values/Value.js';
|
|
2
2
|
import DomTarget from './DomTarget.js';
|
|
3
3
|
import StyleValue from '../values/StyleValue.js';
|
|
4
|
+
import type TestDomNode from './TestDomNode.js';
|
|
5
|
+
import ObjectTarget from './ObjectTarget.js';
|
|
6
|
+
|
|
7
|
+
export type Targets = AnimationTarget | AnimationTarget[];
|
|
8
|
+
export type AnimationTarget =
|
|
9
|
+
| HTMLElement
|
|
10
|
+
| SVGElement
|
|
11
|
+
| TestDomNode
|
|
12
|
+
| Record<string, any>;
|
|
4
13
|
|
|
5
14
|
export function newTarget(target: any): Target {
|
|
6
15
|
if (typeof window === 'undefined') {
|
|
@@ -19,6 +28,10 @@ export function newTarget(target: any): Target {
|
|
|
19
28
|
}
|
|
20
29
|
}
|
|
21
30
|
|
|
31
|
+
if (typeof target === 'object' && target !== null) {
|
|
32
|
+
return new ObjectTarget(target);
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
throw new Error('unknown target');
|
|
23
36
|
}
|
|
24
37
|
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import TestTicker from '../timing/TestTicker.js';
|
|
3
3
|
import TestResponsiveEvent from '../responsive/TestEvent.js';
|
|
4
4
|
import { animate, timeline } from '../chnobli.js';
|
|
5
|
-
import { responsive, curve } from '../utils/utils.js';
|
|
5
|
+
import { responsive, curve, fromTo } from '../utils/utils.js';
|
|
6
6
|
import { el } from '../target/TestDomNode.js';
|
|
7
7
|
import { timeout } from 'fire/utils';
|
|
8
8
|
|
|
@@ -180,4 +180,54 @@ describe('properties', () => {
|
|
|
180
180
|
'translate3d(50.000px,20.000px,0.000px)',
|
|
181
181
|
);
|
|
182
182
|
});
|
|
183
|
+
|
|
184
|
+
it('object-target', () => {
|
|
185
|
+
const ticker = new TestTicker();
|
|
186
|
+
|
|
187
|
+
const obj: { x: number; width?: number } = {
|
|
188
|
+
x: 0,
|
|
189
|
+
};
|
|
190
|
+
const tl = timeline()
|
|
191
|
+
.add(obj, {
|
|
192
|
+
x: 100,
|
|
193
|
+
width: fromTo(0, 100),
|
|
194
|
+
duration: 10,
|
|
195
|
+
})
|
|
196
|
+
.play();
|
|
197
|
+
|
|
198
|
+
ticker.run(5);
|
|
199
|
+
expect(obj.x).toBe(50);
|
|
200
|
+
expect(obj.width).toBe(50);
|
|
201
|
+
|
|
202
|
+
ticker.run();
|
|
203
|
+
expect(obj.x).toBe(100);
|
|
204
|
+
expect(obj.width).toBe(100);
|
|
205
|
+
|
|
206
|
+
tl.reverse();
|
|
207
|
+
tl.play();
|
|
208
|
+
ticker.run();
|
|
209
|
+
expect(obj.x).toBe(undefined);
|
|
210
|
+
expect(obj.width).toBe(undefined);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('reset values', () => {
|
|
214
|
+
const ticker = new TestTicker();
|
|
215
|
+
|
|
216
|
+
const div = el();
|
|
217
|
+
div.computedStyle.width = '0px';
|
|
218
|
+
const tl = timeline()
|
|
219
|
+
.add(div, {
|
|
220
|
+
width: 100,
|
|
221
|
+
duration: 10,
|
|
222
|
+
})
|
|
223
|
+
.play();
|
|
224
|
+
|
|
225
|
+
ticker.run();
|
|
226
|
+
expect(div.style.width).toBe('100.000px');
|
|
227
|
+
|
|
228
|
+
tl.reverse();
|
|
229
|
+
tl.play();
|
|
230
|
+
ticker.run();
|
|
231
|
+
expect(div.style.width).toBe(undefined);
|
|
232
|
+
});
|
|
183
233
|
});
|
package/src/timeline/Nested.ts
CHANGED
|
@@ -24,7 +24,7 @@ type Entry = {
|
|
|
24
24
|
* Timeline is the most versatile class
|
|
25
25
|
*
|
|
26
26
|
* A timeline can contain multiple animation, ordered one after the other or
|
|
27
|
-
* offset.
|
|
27
|
+
* by an offset.
|
|
28
28
|
*/
|
|
29
29
|
export default class Timeline {
|
|
30
30
|
timing: Timing;
|
|
@@ -49,6 +49,8 @@ export default class Timeline {
|
|
|
49
49
|
*/
|
|
50
50
|
constructor(props: Record<string, any> = {}) {
|
|
51
51
|
const nProps = {
|
|
52
|
+
// duration here is not important since it will be calculated
|
|
53
|
+
// based on the animations that get added
|
|
52
54
|
duration: 1000,
|
|
53
55
|
ease: parseEase(takeProp(props, 'ease', null)),
|
|
54
56
|
repeat: parseRepeat(takeProp(props, 'repeat', false)),
|
|
@@ -145,6 +147,21 @@ export default class Timeline {
|
|
|
145
147
|
this._updateTimings();
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Returns the position of a label
|
|
152
|
+
*
|
|
153
|
+
* needs to be initialized
|
|
154
|
+
*/
|
|
155
|
+
labelPosition(label: string): number {
|
|
156
|
+
const entry = this.entries.find(e => {
|
|
157
|
+
return e.type === 'label' && e.value === label;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (!entry) throw new Error('could not find label ' + label);
|
|
161
|
+
|
|
162
|
+
return entry.start! / this.timing.duration;
|
|
163
|
+
}
|
|
164
|
+
|
|
148
165
|
init() {
|
|
149
166
|
if (this._initialized) return;
|
|
150
167
|
this._initialized = true;
|
|
@@ -254,6 +271,9 @@ export default class Timeline {
|
|
|
254
271
|
}
|
|
255
272
|
}
|
|
256
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Updates the timings of all animations
|
|
276
|
+
*/
|
|
257
277
|
_updateTimings() {
|
|
258
278
|
this._renderQueue = {
|
|
259
279
|
upcoming: [],
|
package/src/timeline/public.ts
CHANGED
|
@@ -1,19 +1,49 @@
|
|
|
1
1
|
import { takeProp } from '../utils/internal.js';
|
|
2
|
-
import Timeline from './
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import Timeline from './Timeline.js';
|
|
3
|
+
import Timing, {
|
|
4
|
+
STATE_BEFORE,
|
|
5
|
+
STATE_ENDED,
|
|
6
|
+
TimingProps,
|
|
7
|
+
} from '../timing/Timing.js';
|
|
8
|
+
import Stagger, { callStagger } from '../stagger/stagger.js';
|
|
5
9
|
import Events from '../utils/Events.js';
|
|
6
10
|
import ResponsiveEvent from '../responsive/ResponsiveEvent.js';
|
|
7
11
|
import NestedTimeline from './Nested.js';
|
|
12
|
+
import { Targets } from '../chnobli.js';
|
|
8
13
|
|
|
9
14
|
const STATE_PAUSED = 0;
|
|
10
15
|
const STATE_RENDER_ONCE = 1;
|
|
11
|
-
const
|
|
16
|
+
const STATE_SEEK = 2;
|
|
17
|
+
const STATE_PLAYING = 3;
|
|
12
18
|
|
|
13
19
|
export type Responsive = {
|
|
14
20
|
responsive: () => void;
|
|
15
21
|
};
|
|
16
22
|
|
|
23
|
+
export type TimelineProps = {
|
|
24
|
+
// default properties for all animations
|
|
25
|
+
defaults?: Record<string, any>;
|
|
26
|
+
|
|
27
|
+
// make the timeline responsive default is true
|
|
28
|
+
// this means the timeline will update on resize
|
|
29
|
+
responsive?: boolean;
|
|
30
|
+
|
|
31
|
+
// ease
|
|
32
|
+
ease?: (t: number) => number;
|
|
33
|
+
|
|
34
|
+
// smoothSeek
|
|
35
|
+
smoothSeek?: SmoothSeekValue;
|
|
36
|
+
|
|
37
|
+
// repeat
|
|
38
|
+
// alternate
|
|
39
|
+
// reversed
|
|
40
|
+
|
|
41
|
+
// other properties
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type Offset = number | string | Stagger<number | string>;
|
|
46
|
+
|
|
17
47
|
export default class PublicTimeline {
|
|
18
48
|
/**
|
|
19
49
|
* @ignore
|
|
@@ -27,14 +57,17 @@ export default class PublicTimeline {
|
|
|
27
57
|
_inner: Timeline;
|
|
28
58
|
|
|
29
59
|
private _events: Events;
|
|
60
|
+
private _triggeredStart: boolean;
|
|
30
61
|
|
|
31
62
|
private _state: number;
|
|
32
63
|
private _renderedOnce: boolean;
|
|
33
64
|
private _runningTicker: any;
|
|
34
65
|
private _responsiveBlocks: { responsive: () => void }[];
|
|
35
66
|
private _responsiveEvent: any;
|
|
67
|
+
private _smoothSeek: SmoothSeek | null;
|
|
68
|
+
private _seekTo: number;
|
|
36
69
|
|
|
37
|
-
constructor(props:
|
|
70
|
+
constructor(props: TimelineProps = {}) {
|
|
38
71
|
this._defaults = takeProp(props, 'defaults', {});
|
|
39
72
|
this._responsive = takeProp(props, 'responsive', true);
|
|
40
73
|
|
|
@@ -43,10 +76,16 @@ export default class PublicTimeline {
|
|
|
43
76
|
if ('duration' in props)
|
|
44
77
|
throw new Error('a timeline does not accept a duration');
|
|
45
78
|
|
|
79
|
+
this._smoothSeek = parseSmoothSeek(
|
|
80
|
+
takeProp<SmoothSeekValue>(props, 'smoothSeek', undefined),
|
|
81
|
+
);
|
|
82
|
+
this._seekTo = 0;
|
|
83
|
+
|
|
46
84
|
this._inner = new Timeline(props);
|
|
47
85
|
|
|
48
86
|
// 'start', 'end'
|
|
49
87
|
this._events = new Events();
|
|
88
|
+
this._triggeredStart = false;
|
|
50
89
|
|
|
51
90
|
this._state = STATE_PAUSED;
|
|
52
91
|
this._renderedOnce = false;
|
|
@@ -70,9 +109,10 @@ export default class PublicTimeline {
|
|
|
70
109
|
|
|
71
110
|
/**
|
|
72
111
|
* Set's properties
|
|
112
|
+
*
|
|
73
113
|
* offset can be staggered, a number, a label or a string `+=10`
|
|
74
114
|
*/
|
|
75
|
-
set(targets:
|
|
115
|
+
set(targets: Targets, props: Record<string, any>, offset?: Offset): this {
|
|
76
116
|
// for the moment let's just add as usual but set the duration to 0
|
|
77
117
|
return this.add(targets, { ...props, duration: 0 }, offset);
|
|
78
118
|
}
|
|
@@ -82,14 +122,14 @@ export default class PublicTimeline {
|
|
|
82
122
|
*
|
|
83
123
|
* offset can be staggered, a number, a label or a string `+=10`
|
|
84
124
|
*/
|
|
85
|
-
add(targets:
|
|
125
|
+
add(targets: Targets, props: Record<string, any>, offset?: Offset): this {
|
|
86
126
|
timelineAdd(this, targets, props, offset);
|
|
87
127
|
|
|
88
128
|
return this;
|
|
89
129
|
}
|
|
90
130
|
|
|
91
131
|
/**
|
|
92
|
-
* Adds a label at to the current
|
|
132
|
+
* Adds a label at to the current nOffset
|
|
93
133
|
*
|
|
94
134
|
* This label can then be used in offsets
|
|
95
135
|
*/
|
|
@@ -170,13 +210,14 @@ export default class PublicTimeline {
|
|
|
170
210
|
seekMs(ms: number) {
|
|
171
211
|
this._inner.init();
|
|
172
212
|
|
|
173
|
-
this._inner.
|
|
174
|
-
|
|
175
|
-
if (this._state !== STATE_PLAYING) this._state = STATE_RENDER_ONCE;
|
|
176
|
-
|
|
177
|
-
this._startTicker();
|
|
213
|
+
this.seek(this._inner.timing.normalizeMs(ms));
|
|
178
214
|
}
|
|
179
215
|
|
|
216
|
+
// todo maybe we should have two functions
|
|
217
|
+
// seek
|
|
218
|
+
// and setPosition
|
|
219
|
+
// seek would include reverse but setPosition would not
|
|
220
|
+
|
|
180
221
|
/**
|
|
181
222
|
* Seeks to a normalized position in the timeline
|
|
182
223
|
*
|
|
@@ -185,19 +226,37 @@ export default class PublicTimeline {
|
|
|
185
226
|
seek(pos: number) {
|
|
186
227
|
this._inner.init();
|
|
187
228
|
|
|
188
|
-
this.
|
|
229
|
+
if (this._smoothSeek) {
|
|
230
|
+
this._smoothSeek.update(this._inner.timing.positionLinear(), pos);
|
|
231
|
+
|
|
232
|
+
if (this._state !== STATE_PLAYING) this._state = STATE_SEEK;
|
|
233
|
+
} else {
|
|
234
|
+
// this._inner.seek(pos);
|
|
235
|
+
this._seekTo = pos;
|
|
189
236
|
|
|
190
|
-
|
|
237
|
+
if (this._state !== STATE_PLAYING) this._state = STATE_RENDER_ONCE;
|
|
238
|
+
}
|
|
191
239
|
|
|
192
240
|
this._startTicker();
|
|
193
241
|
}
|
|
194
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Returns the position of a label
|
|
245
|
+
*/
|
|
246
|
+
labelPosition(label: string): number {
|
|
247
|
+
this._inner.init();
|
|
248
|
+
|
|
249
|
+
return this._inner.labelPosition(label);
|
|
250
|
+
}
|
|
251
|
+
|
|
195
252
|
// seek in Range (useful for scroll timelines)
|
|
196
253
|
// seek(startOffset, endOffset, pos)
|
|
197
254
|
|
|
198
255
|
/**
|
|
199
256
|
* Resets the current timeline to the start
|
|
200
257
|
* without changing anything
|
|
258
|
+
*
|
|
259
|
+
* this operation is not smooth use seek 0 if you wan't that
|
|
201
260
|
*/
|
|
202
261
|
reset() {
|
|
203
262
|
this._inner.seek(0);
|
|
@@ -244,6 +303,8 @@ export default class PublicTimeline {
|
|
|
244
303
|
*/
|
|
245
304
|
reverse() {
|
|
246
305
|
this._inner.timing.reverse();
|
|
306
|
+
|
|
307
|
+
// todo does this work with smooth seek?
|
|
247
308
|
}
|
|
248
309
|
|
|
249
310
|
/**
|
|
@@ -280,6 +341,13 @@ export default class PublicTimeline {
|
|
|
280
341
|
this._inner = null;
|
|
281
342
|
}
|
|
282
343
|
|
|
344
|
+
_maybeTriggerEndEvent() {
|
|
345
|
+
if (this._state !== STATE_PLAYING) return;
|
|
346
|
+
|
|
347
|
+
this._events.trigger('end');
|
|
348
|
+
this._triggeredStart = false;
|
|
349
|
+
}
|
|
350
|
+
|
|
283
351
|
/**
|
|
284
352
|
* @ignore
|
|
285
353
|
*/
|
|
@@ -288,48 +356,45 @@ export default class PublicTimeline {
|
|
|
288
356
|
|
|
289
357
|
this._inner.init();
|
|
290
358
|
|
|
359
|
+
const timingEnded = () => this._inner.timing.state >= STATE_ENDED;
|
|
360
|
+
const smoothSeekEnded = () =>
|
|
361
|
+
!this._smoothSeek || this._smoothSeek.state >= STATE_ENDED;
|
|
362
|
+
|
|
291
363
|
this._runningTicker = this._inner.ticker.add(change => {
|
|
292
|
-
if (this.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
this.
|
|
364
|
+
if (!this._triggeredStart) {
|
|
365
|
+
// todo check that we are at the start
|
|
366
|
+
if (this._inner.timing.state <= STATE_BEFORE) {
|
|
367
|
+
this._events.trigger('start');
|
|
368
|
+
this._triggeredStart = true;
|
|
296
369
|
}
|
|
297
|
-
|
|
298
|
-
if (this._state === STATE_PLAYING) this._events.trigger('end');
|
|
299
|
-
|
|
300
|
-
this._state = STATE_PAUSED;
|
|
301
|
-
this._stopTicker();
|
|
302
|
-
return;
|
|
303
370
|
}
|
|
304
371
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
372
|
+
const allowSmoothSeek =
|
|
373
|
+
this._state === STATE_PLAYING || this._state === STATE_SEEK;
|
|
374
|
+
if (
|
|
375
|
+
allowSmoothSeek &&
|
|
376
|
+
this._smoothSeek &&
|
|
377
|
+
this._smoothSeek.state < STATE_ENDED
|
|
378
|
+
) {
|
|
379
|
+
this._smoothSeek.advance(change);
|
|
380
|
+
this._inner.seek(this._smoothSeek.value);
|
|
381
|
+
} else if (this._state === STATE_RENDER_ONCE) {
|
|
382
|
+
this._inner.seek(this._seekTo);
|
|
383
|
+
} else if (this._state === STATE_PLAYING) {
|
|
384
|
+
this._inner.advance(change);
|
|
385
|
+
}
|
|
318
386
|
|
|
319
387
|
this._inner.render();
|
|
320
388
|
|
|
321
|
-
|
|
322
|
-
|
|
389
|
+
// we rendered once let's stop
|
|
390
|
+
const renderOnce = this._state === STATE_RENDER_ONCE;
|
|
323
391
|
|
|
324
|
-
|
|
325
|
-
this.
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
392
|
+
if (renderOnce || (timingEnded() && smoothSeekEnded())) {
|
|
393
|
+
this._maybeTriggerEndEvent();
|
|
328
394
|
|
|
329
|
-
// we rendered once let's stop
|
|
330
|
-
if (this._state === STATE_RENDER_ONCE) {
|
|
331
395
|
this._state = STATE_PAUSED;
|
|
332
396
|
this._stopTicker();
|
|
397
|
+
return;
|
|
333
398
|
}
|
|
334
399
|
});
|
|
335
400
|
}
|
|
@@ -384,8 +449,64 @@ export function timelineAdd(
|
|
|
384
449
|
nProps[prop] = callStagger(nProps[prop], i, targets.length);
|
|
385
450
|
}
|
|
386
451
|
|
|
387
|
-
const nOffset = callStagger(offset, i);
|
|
452
|
+
const nOffset = callStagger(offset, i, targets.length);
|
|
388
453
|
|
|
389
454
|
tl._inner.add(target, nProps, nOffset, i);
|
|
390
455
|
}
|
|
391
456
|
}
|
|
457
|
+
|
|
458
|
+
export type SmoothSeekValue =
|
|
459
|
+
| number
|
|
460
|
+
| undefined
|
|
461
|
+
| { duration: number; ease?: (t: number) => number };
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Smooth seek
|
|
465
|
+
*
|
|
466
|
+
* can either just be a number (duration) or an object { duration, ease }
|
|
467
|
+
*/
|
|
468
|
+
function parseSmoothSeek(smoothSeek: SmoothSeekValue): SmoothSeek | null {
|
|
469
|
+
if (!smoothSeek) return null;
|
|
470
|
+
|
|
471
|
+
if (typeof smoothSeek === 'number') {
|
|
472
|
+
return new SmoothSeek({
|
|
473
|
+
duration: smoothSeek,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return new SmoothSeek({
|
|
478
|
+
duration: smoothSeek.duration,
|
|
479
|
+
ease: smoothSeek?.ease,
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
class SmoothSeek {
|
|
484
|
+
timing: Timing;
|
|
485
|
+
from: number;
|
|
486
|
+
to: number;
|
|
487
|
+
|
|
488
|
+
constructor(timing: TimingProps) {
|
|
489
|
+
this.timing = new Timing(timing);
|
|
490
|
+
this.timing.seek(1);
|
|
491
|
+
this.from = 0;
|
|
492
|
+
this.to = 0;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
update(from: number, to: number) {
|
|
496
|
+
this.from = from;
|
|
497
|
+
this.to = to;
|
|
498
|
+
this.timing.seek(0);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
advance(change: number) {
|
|
502
|
+
this.timing.advance(change);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
get value(): number {
|
|
506
|
+
return this.from + (this.to - this.from) * this.timing.position;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
get state(): number {
|
|
510
|
+
return this.timing.state;
|
|
511
|
+
}
|
|
512
|
+
}
|
package/src/timing/Timing.ts
CHANGED
|
@@ -12,6 +12,14 @@ export type Position = {
|
|
|
12
12
|
progress: number;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export type TimingProps = {
|
|
16
|
+
duration: number;
|
|
17
|
+
ease?: (t: number) => number;
|
|
18
|
+
repeat?: number;
|
|
19
|
+
alternate?: boolean;
|
|
20
|
+
reversed?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
15
23
|
/**
|
|
16
24
|
* This class handles everything timing related
|
|
17
25
|
*
|
|
@@ -58,7 +66,7 @@ export default class Timing {
|
|
|
58
66
|
alternate
|
|
59
67
|
}
|
|
60
68
|
*/
|
|
61
|
-
constructor(props:
|
|
69
|
+
constructor(props: TimingProps) {
|
|
62
70
|
// these vars are only readonly
|
|
63
71
|
// use functions to update them
|
|
64
72
|
|
|
@@ -90,6 +98,7 @@ export default class Timing {
|
|
|
90
98
|
}
|
|
91
99
|
|
|
92
100
|
positionMs() {
|
|
101
|
+
// todo should this not return pos * duration?
|
|
93
102
|
return this.position * this.iterDuration;
|
|
94
103
|
}
|
|
95
104
|
|
|
@@ -132,6 +141,31 @@ export default class Timing {
|
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
this._updateProgress(ms / this.iterDuration);
|
|
144
|
+
|
|
145
|
+
// return this.seek(this.normalizeMs(ms));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
normalizeMs(ms: number) {
|
|
149
|
+
if (this.iterDuration <= 0) {
|
|
150
|
+
return Math.sign(ms);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const pos = ms / this.iterDuration;
|
|
154
|
+
|
|
155
|
+
if (this.isFinite()) {
|
|
156
|
+
return pos / (this.repeat + 1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return pos;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// todo how to call this
|
|
163
|
+
positionLinear(): number {
|
|
164
|
+
if (this.isFinite()) {
|
|
165
|
+
return this._progress / (this.repeat + 1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return this._progress;
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
// should be between 0-1 if outside might change the state
|
|
@@ -241,7 +275,7 @@ export default class Timing {
|
|
|
241
275
|
}
|
|
242
276
|
}
|
|
243
277
|
|
|
244
|
-
export function newTiming(props: Record<string, any>) {
|
|
278
|
+
export function newTiming(props: Record<string, any>): Timing {
|
|
245
279
|
const nProps = {
|
|
246
280
|
duration: parseDuration(takeProp(props, 'duration', 1000)),
|
|
247
281
|
ease: parseEase(takeProp(props, 'ease', null)),
|
|
@@ -253,7 +287,7 @@ export function newTiming(props: Record<string, any>) {
|
|
|
253
287
|
return new Timing(nProps);
|
|
254
288
|
}
|
|
255
289
|
|
|
256
|
-
export function parseDuration(dur: any) {
|
|
290
|
+
export function parseDuration(dur: any): number {
|
|
257
291
|
if (typeof dur !== 'number') throw new Error('duration is not a number');
|
|
258
292
|
|
|
259
293
|
dur = Math.round(dur);
|
package/src/utils/internal.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Take a property from an object and delete it from the object.
|
|
3
|
+
*/
|
|
4
|
+
export function takeProp<T>(
|
|
2
5
|
props: Record<string, any>,
|
|
3
6
|
name: string,
|
|
4
|
-
def:
|
|
5
|
-
):
|
|
7
|
+
def: T,
|
|
8
|
+
): T {
|
|
6
9
|
const v = props[name] ?? def;
|
|
7
10
|
delete props[name];
|
|
8
11
|
|