@needle-tools/engine 4.9.3 → 4.10.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.
- package/CHANGELOG.md +9 -0
- package/components.needle.json +1 -1
- package/dist/{gltf-progressive-DhE1A6hX.min.js → gltf-progressive-CoZbSfPR.min.js} +1 -1
- package/dist/{gltf-progressive-egsMzRdv.js → gltf-progressive-DUR9TuAH.js} +3 -3
- package/dist/{gltf-progressive-DWiyqrwB.umd.cjs → gltf-progressive-Iy7aSAPk.umd.cjs} +1 -1
- package/dist/{needle-engine.bundle-C7LSzO5L.umd.cjs → needle-engine.bundle-42AmEGfk.umd.cjs} +160 -137
- package/dist/needle-engine.bundle-C6zhyLF5.min.js +1639 -0
- package/dist/{needle-engine.bundle-BAsxNKpA.js → needle-engine.bundle-Dj6faVbC.js} +7665 -7380
- package/dist/needle-engine.js +447 -444
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/{postprocessing-BZOSD1ln.min.js → postprocessing-BHMVuZQ1.min.js} +1 -1
- package/dist/{postprocessing-Bb5StX0o.umd.cjs → postprocessing-BsnRNRRS.umd.cjs} +1 -1
- package/dist/{postprocessing-BzFF7i-7.js → postprocessing-DQ2pynXW.js} +2 -2
- package/dist/{three-BK56xWDs.umd.cjs → three-B-jwTHao.umd.cjs} +11 -11
- package/dist/{three-CsHK73Zc.js → three-CJSAehtG.js} +1 -0
- package/dist/{three-examples-Bph291U2.min.js → three-examples-BivkhnvN.min.js} +1 -1
- package/dist/{three-examples-C9WfZu-X.umd.cjs → three-examples-Deqc1bNw.umd.cjs} +1 -1
- package/dist/{three-examples-BvMpKSun.js → three-examples-Doq0rvFU.js} +1 -1
- package/dist/{three-mesh-ui-CN6aRT7i.js → three-mesh-ui-CktOi6oI.js} +1 -1
- package/dist/{three-mesh-ui-DnxkZWNA.umd.cjs → three-mesh-ui-CsHwj9cJ.umd.cjs} +1 -1
- package/dist/{three-mesh-ui-n_qS2BM-.min.js → three-mesh-ui-DhYXcXZe.min.js} +1 -1
- package/dist/{three-TNFQHSFa.min.js → three-qw28ZtTy.min.js} +10 -10
- package/dist/{vendor-BtJpSuCj.umd.cjs → vendor-D0Yvltn9.umd.cjs} +1 -1
- package/dist/{vendor-k9i6CeGi.js → vendor-DU8tJyl_.js} +1 -1
- package/dist/{vendor-XJ9xiwrv.min.js → vendor-JyrX4DVM.min.js} +1 -1
- package/lib/engine/api.d.ts +1 -0
- package/lib/engine/api.js +1 -0
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +4 -0
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_animation.d.ts +21 -1
- package/lib/engine/engine_animation.js +32 -1
- package/lib/engine/engine_animation.js.map +1 -1
- package/lib/engine/engine_camera.fit.d.ts +68 -0
- package/lib/engine/engine_camera.fit.js +193 -0
- package/lib/engine/engine_camera.fit.js.map +1 -0
- package/lib/engine/engine_gizmos.d.ts +2 -2
- package/lib/engine/engine_gizmos.js +2 -2
- package/lib/engine/engine_physics.js +6 -3
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +1 -0
- package/lib/engine/webcomponents/needle-engine.js +6 -0
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +59 -23
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +16 -0
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +8 -9
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +4 -47
- package/lib/engine-components/OrbitControls.js +30 -178
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +2 -2
- package/lib/engine-components/Renderer.js +6 -4
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/api.d.ts +0 -1
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +2 -0
- package/lib/engine-components/codegen/components.js +2 -0
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +28 -6
- package/lib/engine-components/timeline/PlayableDirector.js +60 -26
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineModels.d.ts +3 -0
- package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +7 -0
- package/lib/engine-components/timeline/TimelineTracks.js +19 -0
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.d.ts +3 -0
- package/lib/engine-components/web/Clickthrough.js +3 -0
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +3 -0
- package/lib/engine-components/web/CursorFollow.js +3 -0
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/web/HoverAnimation.d.ts +44 -0
- package/lib/engine-components/web/HoverAnimation.js +105 -0
- package/lib/engine-components/web/HoverAnimation.js.map +1 -0
- package/lib/engine-components/web/ScrollFollow.d.ts +18 -4
- package/lib/engine-components/web/ScrollFollow.js +143 -25
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/index.d.ts +1 -0
- package/lib/engine-components/web/index.js +1 -0
- package/lib/engine-components/web/index.js.map +1 -1
- package/package.json +1 -1
- package/plugins/vite/alias.js +5 -3
- package/plugins/vite/poster-client.js +22 -21
- package/src/engine/api.ts +2 -1
- package/src/engine/codegen/register_types.ts +4 -0
- package/src/engine/engine_animation.ts +69 -1
- package/src/engine/engine_camera.fit.ts +288 -0
- package/src/engine/engine_gizmos.ts +2 -2
- package/src/engine/engine_physics.ts +6 -3
- package/src/engine/webcomponents/needle-engine.loading.ts +63 -24
- package/src/engine/webcomponents/needle-engine.ts +6 -1
- package/src/engine-components/AnimatorController.ts +21 -2
- package/src/engine-components/CameraUtils.ts +8 -9
- package/src/engine-components/OrbitControls.ts +30 -239
- package/src/engine-components/Renderer.ts +6 -4
- package/src/engine-components/api.ts +0 -1
- package/src/engine-components/codegen/components.ts +2 -0
- package/src/engine-components/timeline/PlayableDirector.ts +79 -34
- package/src/engine-components/timeline/TimelineModels.ts +3 -0
- package/src/engine-components/timeline/TimelineTracks.ts +22 -0
- package/src/engine-components/web/Clickthrough.ts +3 -0
- package/src/engine-components/web/CursorFollow.ts +3 -0
- package/src/engine-components/web/HoverAnimation.ts +99 -0
- package/src/engine-components/web/ScrollFollow.ts +181 -24
- package/src/engine-components/web/index.ts +1 -0
- package/dist/needle-engine.bundle-ugr1bBtk.min.js +0 -1616
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { AnimationClip } from "three";
|
|
2
|
+
|
|
3
|
+
import { ScaleClipType } from "../../engine/engine_animation.js";
|
|
4
|
+
import { AnimationUtils } from "../../engine/engine_animation.js";
|
|
5
|
+
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
|
6
|
+
import { registerType } from "../../engine/engine_typestore.js";
|
|
7
|
+
import { Animation } from "../Animation.js";
|
|
8
|
+
import { Behaviour } from "../Component.js";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @category Web
|
|
13
|
+
* @group Components
|
|
14
|
+
* @component
|
|
15
|
+
*/
|
|
16
|
+
@registerType
|
|
17
|
+
export class HoverAnimation extends Behaviour {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default hover animation type if no custom clip is provided.
|
|
21
|
+
* **Node**: This is only used if no custom hover animation clip is provided.
|
|
22
|
+
* @default "linear"
|
|
23
|
+
*/
|
|
24
|
+
@serializable()
|
|
25
|
+
type: ScaleClipType = "linear";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Duration of the hover animation in seconds.
|
|
29
|
+
* **Node**: This is only used if no custom hover animation clip is provided.
|
|
30
|
+
* @default 0.1
|
|
31
|
+
*/
|
|
32
|
+
@serializable()
|
|
33
|
+
duration: number = 0.1;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Scale factor to apply when hovering.
|
|
37
|
+
* **Node**: This is only used if no custom hover animation clip is provided.
|
|
38
|
+
* @default 1.1
|
|
39
|
+
*/
|
|
40
|
+
@serializable()
|
|
41
|
+
scaleFactor: number = 1.1;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Animation clip to play when hovering. If null, a default scale-up animation is used.
|
|
46
|
+
*/
|
|
47
|
+
@serializable(AnimationClip)
|
|
48
|
+
hovered: AnimationClip | null = null;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Animation clip to play when not hovering. If null, an empty clip is used.
|
|
52
|
+
*/
|
|
53
|
+
@serializable(AnimationClip)
|
|
54
|
+
idle: AnimationClip | null = null;
|
|
55
|
+
|
|
56
|
+
private animation: Animation | null = null;
|
|
57
|
+
|
|
58
|
+
start() {
|
|
59
|
+
if (!this.idle) this.idle = AnimationUtils.emptyClip();
|
|
60
|
+
|
|
61
|
+
if (!this.hovered) {
|
|
62
|
+
this.hovered = AnimationUtils.createScaleClip({
|
|
63
|
+
type: "linear",
|
|
64
|
+
duration: this.duration || 0.1,
|
|
65
|
+
scale: this.gameObject.scale,
|
|
66
|
+
scaleFactor: this.scaleFactor || 1.1,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.animation ??= this.gameObject.addComponent(Animation);
|
|
71
|
+
this.animation.playAutomatically = false;
|
|
72
|
+
this.playIdle();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onEnable() {
|
|
76
|
+
if (this.animation) this.animation.enabled = true;
|
|
77
|
+
this.playIdle();
|
|
78
|
+
}
|
|
79
|
+
onDisable() {
|
|
80
|
+
if (this.animation) this.animation.enabled = false;
|
|
81
|
+
this.playIdle();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onPointerEnter() {
|
|
85
|
+
this.playHover();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onPointerExit() {
|
|
89
|
+
this.playIdle();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private playIdle() {
|
|
93
|
+
if (this.idle) this.animation?.play(this.idle, { exclusive: true, fadeDuration: .1, loop: true });
|
|
94
|
+
}
|
|
95
|
+
private playHover() {
|
|
96
|
+
if (this.hovered) this.animation?.play(this.hovered, { exclusive: true, fadeDuration: .1, loop: false, clampWhenFinished: true });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Box3, Object3D } from "three";
|
|
2
|
+
import { element } from "three/src/nodes/TSL.js";
|
|
3
|
+
import { Context } from "../../engine/engine_context.js";
|
|
2
4
|
|
|
3
5
|
import { Mathf } from "../../engine/engine_math.js";
|
|
4
6
|
import { serializable } from "../../engine/engine_serialization.js";
|
|
5
7
|
import { getBoundingBox } from "../../engine/engine_three_utils.js";
|
|
8
|
+
import { getParam } from "../../engine/engine_utils.js";
|
|
6
9
|
import { Animation } from "../Animation.js";
|
|
7
10
|
import { Animator } from "../Animator.js";
|
|
8
11
|
import { AudioSource } from "../AudioSource.js";
|
|
@@ -11,6 +14,9 @@ import { EventList } from "../EventList.js";
|
|
|
11
14
|
import { Light } from "../Light.js";
|
|
12
15
|
import { SplineWalker } from "../splines/SplineWalker.js";
|
|
13
16
|
import { PlayableDirector } from "../timeline/PlayableDirector.js";
|
|
17
|
+
import { ScrollMarkerModel } from "../timeline/TimelineModels.js";
|
|
18
|
+
|
|
19
|
+
const debug = getParam("debugscroll");
|
|
14
20
|
|
|
15
21
|
type ScrollFollowEvent = {
|
|
16
22
|
/** Event type */
|
|
@@ -44,6 +50,10 @@ type ScrollFollowEvent = {
|
|
|
44
50
|
* 2. Add a ScrollFollow component to the same GameObject or another GameObject in the scene.
|
|
45
51
|
* 3. Assign the PlayableDirector component to the ScrollFollow's target property.
|
|
46
52
|
* 4. The timeline will now scrub based on the scroll position of the page.
|
|
53
|
+
*
|
|
54
|
+
* @category Web
|
|
55
|
+
* @group Components
|
|
56
|
+
* @component
|
|
47
57
|
*/
|
|
48
58
|
export class ScrollFollow extends Behaviour {
|
|
49
59
|
|
|
@@ -77,7 +87,8 @@ export class ScrollFollow extends Behaviour {
|
|
|
77
87
|
@serializable()
|
|
78
88
|
invert: boolean = false;
|
|
79
89
|
|
|
80
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* **Experimental - might change in future updates**
|
|
81
92
|
* If set, the scroll position will be read from the specified element instead of the window.
|
|
82
93
|
* Use a CSS selector to specify the element, e.g. `#my-scrollable-div` or `.scroll-container`.
|
|
83
94
|
* @default null
|
|
@@ -98,17 +109,23 @@ export class ScrollFollow extends Behaviour {
|
|
|
98
109
|
* Current scroll value in "pages" (0 = top of page, 1 = bottom of page)
|
|
99
110
|
*/
|
|
100
111
|
get currentValue() {
|
|
101
|
-
return this.
|
|
112
|
+
return this._current_value;
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
private
|
|
105
|
-
private
|
|
106
|
-
private
|
|
115
|
+
private _current_value: number = 0;
|
|
116
|
+
private _target_value: number = 0;
|
|
117
|
+
private _appliedValue: number = -1;
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
private _scrollStart: number = 0;
|
|
121
|
+
private _scrollEnd: number = 0;
|
|
122
|
+
private _scrollValue: number = 0;
|
|
123
|
+
private _scrollContainerHeight: number = 0;
|
|
107
124
|
|
|
108
125
|
/** @internal */
|
|
109
126
|
onEnable() {
|
|
110
127
|
window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
|
|
111
|
-
this.
|
|
128
|
+
this._appliedValue = -1;
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
/** @internal */
|
|
@@ -121,23 +138,27 @@ export class ScrollFollow extends Behaviour {
|
|
|
121
138
|
|
|
122
139
|
this.updateCurrentScrollValue();
|
|
123
140
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
141
|
+
if (this._target_value >= 0) {
|
|
142
|
+
if (this.damping > 0) { // apply damping
|
|
143
|
+
this._current_value = Mathf.lerp(this._current_value, this._target_value, this.context.time.deltaTime / this.damping);
|
|
144
|
+
if (Math.abs(this._current_value - this._target_value) < 0.001) {
|
|
145
|
+
this._current_value = this._target_value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this._current_value = this._target_value;
|
|
150
|
+
}
|
|
130
151
|
}
|
|
131
152
|
|
|
132
|
-
if (this.
|
|
133
|
-
this.
|
|
153
|
+
if (this._current_value !== this._appliedValue) {
|
|
154
|
+
this._appliedValue = this._current_value;
|
|
134
155
|
|
|
135
156
|
let defaultPrevented = false;
|
|
136
157
|
if (this.changed.listenerCount > 0) {
|
|
137
158
|
// fire change event
|
|
138
159
|
const event: ScrollFollowEvent = {
|
|
139
160
|
type: "change",
|
|
140
|
-
value: this.
|
|
161
|
+
value: this._current_value,
|
|
141
162
|
component: this,
|
|
142
163
|
preventDefault: () => { event.defaultPrevented = true; },
|
|
143
164
|
defaultPrevented: false,
|
|
@@ -149,14 +170,21 @@ export class ScrollFollow extends Behaviour {
|
|
|
149
170
|
// if not prevented apply scroll
|
|
150
171
|
if (!defaultPrevented) {
|
|
151
172
|
|
|
152
|
-
const value = this.invert ? 1 - this.
|
|
173
|
+
const value = this.invert ? 1 - this._current_value : this._current_value;
|
|
174
|
+
|
|
175
|
+
const height = this._rangeEndValue - this._rangeStartValue;
|
|
176
|
+
const pixelValue = this._rangeStartValue + value * height;
|
|
153
177
|
|
|
154
178
|
// apply scroll to target(s)
|
|
155
179
|
if (Array.isArray(this.target)) {
|
|
156
|
-
this.target.forEach(t => t &&
|
|
180
|
+
this.target.forEach(t => t && this.applyScroll(t, value));
|
|
157
181
|
}
|
|
158
182
|
else if (this.target) {
|
|
159
|
-
|
|
183
|
+
this.applyScroll(this.target, value);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (debug && this.context.time.frame % 30 === 0) {
|
|
187
|
+
console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%`);
|
|
160
188
|
}
|
|
161
189
|
}
|
|
162
190
|
}
|
|
@@ -164,11 +192,16 @@ export class ScrollFollow extends Behaviour {
|
|
|
164
192
|
|
|
165
193
|
private _lastSelectorValue: string | null = null;
|
|
166
194
|
private _lastSelectorElement: Element | null = null;
|
|
195
|
+
/** Top y */
|
|
196
|
+
private _rangeStartValue: number = 0;
|
|
197
|
+
/** Bottom y */
|
|
198
|
+
private _rangeEndValue: number = 0;
|
|
167
199
|
|
|
168
200
|
private updateCurrentScrollValue = () => {
|
|
169
201
|
|
|
170
202
|
switch (this.mode) {
|
|
171
203
|
case "window":
|
|
204
|
+
|
|
172
205
|
if (this.htmlSelector?.length) {
|
|
173
206
|
if (this.htmlSelector !== this._lastSelectorValue) {
|
|
174
207
|
this._lastSelectorElement = document.querySelector(this.htmlSelector);
|
|
@@ -176,27 +209,39 @@ export class ScrollFollow extends Behaviour {
|
|
|
176
209
|
}
|
|
177
210
|
if (this._lastSelectorElement) {
|
|
178
211
|
const rect = this._lastSelectorElement.getBoundingClientRect();
|
|
179
|
-
|
|
180
|
-
|
|
212
|
+
|
|
213
|
+
this._scrollStart = rect.top + window.scrollY;
|
|
214
|
+
this._scrollEnd = rect.height - window.innerHeight;
|
|
215
|
+
this._scrollValue = -rect.top;
|
|
216
|
+
this._target_value = -rect.top / (rect.height - window.innerHeight);
|
|
217
|
+
this._rangeStartValue = rect.top + window.scrollY;
|
|
218
|
+
this._rangeEndValue = this._rangeStartValue + rect.height - window.innerHeight;
|
|
219
|
+
this._scrollContainerHeight = rect.height;
|
|
181
220
|
break;
|
|
182
221
|
}
|
|
183
222
|
}
|
|
184
223
|
else {
|
|
185
|
-
this.
|
|
224
|
+
this._scrollStart = 0;
|
|
225
|
+
this._scrollEnd = window.document.body.scrollHeight - window.innerHeight;
|
|
226
|
+
this._scrollValue = window.scrollY;
|
|
227
|
+
this._target_value = this._scrollValue / (this._scrollEnd || 1);
|
|
228
|
+
this._rangeStartValue = 0;
|
|
229
|
+
this._rangeEndValue = document.body.scrollHeight;
|
|
230
|
+
this._scrollContainerHeight = window.innerHeight;
|
|
186
231
|
}
|
|
187
|
-
if (isNaN(this.target_value) || !isFinite(this.target_value)) this.target_value = 0;
|
|
188
232
|
break;
|
|
189
233
|
}
|
|
190
234
|
|
|
235
|
+
if (isNaN(this._target_value) || !isFinite(this._target_value)) this._target_value = -1;
|
|
191
236
|
}
|
|
192
237
|
|
|
193
238
|
|
|
194
|
-
private
|
|
239
|
+
private applyScroll(target: object, value: number) {
|
|
195
240
|
|
|
196
241
|
if (!target) return;
|
|
197
242
|
|
|
198
243
|
if (target instanceof PlayableDirector) {
|
|
199
|
-
target
|
|
244
|
+
this.handleTimelineTarget(target, value);
|
|
200
245
|
if (!target.isPlaying) target.evaluate();
|
|
201
246
|
}
|
|
202
247
|
else if (target instanceof Animator) {
|
|
@@ -236,4 +281,116 @@ export class ScrollFollow extends Behaviour {
|
|
|
236
281
|
}
|
|
237
282
|
}
|
|
238
283
|
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
private handleTimelineTarget(director: PlayableDirector, value: number) {
|
|
287
|
+
|
|
288
|
+
const duration = director.duration;
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
let scrollRegionStart = Infinity;
|
|
292
|
+
let scrollRegionEnd = 0;
|
|
293
|
+
markersArray.length = 0;
|
|
294
|
+
|
|
295
|
+
for (const marker of director.foreachMarker<ScrollMarkerModel & { element?: HTMLElement | null, needsUpdate?: boolean }>("ScrollMarker")) {
|
|
296
|
+
|
|
297
|
+
// Get marker elements from DOM
|
|
298
|
+
if (marker.selector?.length && (marker.element === undefined || marker.needsUpdate === true || /** element is not in DOM anymore? */ (!marker.element?.parentNode))) {
|
|
299
|
+
marker.needsUpdate = false;
|
|
300
|
+
try {
|
|
301
|
+
marker.element = document.querySelector<HTMLElement>(marker.selector) || null;
|
|
302
|
+
if (debug) console.debug("ScrollMarker found on page", marker.element, marker.selector);
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
marker.element = null;
|
|
306
|
+
console.error("ScrollMarker selector is not valid: " + marker.selector + "\n", error);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// skip markers without element (e.g. if the selector didn't return any element)
|
|
311
|
+
if (!marker.element) continue;
|
|
312
|
+
|
|
313
|
+
markersArray.push(marker);
|
|
314
|
+
|
|
315
|
+
const top = marker.element.offsetTop;
|
|
316
|
+
const height = marker.element.offsetHeight;
|
|
317
|
+
const bottom = top + height;
|
|
318
|
+
if (top < scrollRegionStart) {
|
|
319
|
+
scrollRegionStart = top;
|
|
320
|
+
}
|
|
321
|
+
if (bottom > scrollRegionEnd) {
|
|
322
|
+
scrollRegionEnd = bottom;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
const currentTop = this._scrollValue;
|
|
329
|
+
const currentBottom = currentTop + this._scrollContainerHeight;
|
|
330
|
+
|
|
331
|
+
weightsArray.length = 0;
|
|
332
|
+
let sum = 0;
|
|
333
|
+
|
|
334
|
+
let markerCount = 0;
|
|
335
|
+
for (const marker of markersArray) {
|
|
336
|
+
|
|
337
|
+
if (!marker.element) continue;
|
|
338
|
+
|
|
339
|
+
const top = marker.element.offsetTop;
|
|
340
|
+
const height = marker.element.offsetHeight;
|
|
341
|
+
const bottom = top + height;
|
|
342
|
+
let overlap = 0;
|
|
343
|
+
|
|
344
|
+
// TODO: if we have two marker sections where no HTML overlaps (vor example because some large section is between them) we probably want to still virtually interpolate between them slowly in that region
|
|
345
|
+
|
|
346
|
+
if (bottom < currentTop) {
|
|
347
|
+
// marker is above scroll region
|
|
348
|
+
overlap = 0;
|
|
349
|
+
}
|
|
350
|
+
else if (top > currentBottom) {
|
|
351
|
+
// marker is below scroll region
|
|
352
|
+
overlap = 0;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
// calculate overlap in pixels
|
|
356
|
+
const overlapTop = Math.max(top, currentTop);
|
|
357
|
+
const overlapBottom = Math.min(bottom, currentBottom);
|
|
358
|
+
overlap = Math.max(0, overlapBottom - overlapTop);
|
|
359
|
+
// console.log(marker.element.className, overlap)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
markerCount += 1;
|
|
363
|
+
|
|
364
|
+
if (overlap > 0) {
|
|
365
|
+
weightsArray.push({ time: marker.time, weight: overlap });
|
|
366
|
+
sum += overlap;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (weightsArray.length <= 0 && markerCount <= 0) {
|
|
371
|
+
director.time = value * duration;
|
|
372
|
+
}
|
|
373
|
+
else if (weightsArray.length > 0) {
|
|
374
|
+
// normalize and calculate weighted time
|
|
375
|
+
let time = weightsArray[0].time;
|
|
376
|
+
for (const o of weightsArray) {
|
|
377
|
+
const weight = o.weight / Math.max(0.00001, sum);
|
|
378
|
+
// lerp time based on weight
|
|
379
|
+
const diff = Math.abs(o.time - time);
|
|
380
|
+
time += diff * weight;
|
|
381
|
+
}
|
|
382
|
+
director.time = time;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const weightsArray: OverlapInfo[] = [];
|
|
389
|
+
const markersArray: (ScrollMarkerModel & { element?: HTMLElement | null })[] = [];
|
|
390
|
+
|
|
391
|
+
type OverlapInfo = {
|
|
392
|
+
/** Marker time */
|
|
393
|
+
time: number,
|
|
394
|
+
/** Overlap in pixels */
|
|
395
|
+
weight: number,
|
|
239
396
|
}
|