@needle-tools/engine 4.11.0 → 4.11.1
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 +6 -0
- package/README.md +3 -1
- package/dist/{needle-engine.bundle-Dh4X0Qy5.js → needle-engine.bundle-6yF8G5KJ.js} +2646 -2575
- package/dist/{needle-engine.bundle-IPerDSpg.min.js → needle-engine.bundle-BSk8yk3v.min.js} +100 -100
- package/dist/{needle-engine.bundle-DhRclTK5.umd.cjs → needle-engine.bundle-DPVYipMl.umd.cjs} +97 -97
- package/dist/needle-engine.js +2 -2
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/lib/engine/engine_physics.js +2 -1
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +2 -0
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/splines/SplineWalker.d.ts +43 -4
- package/lib/engine-components/splines/SplineWalker.js +88 -12
- package/lib/engine-components/splines/SplineWalker.js.map +1 -1
- package/lib/engine-components/web/Clickthrough.d.ts +2 -0
- package/lib/engine-components/web/Clickthrough.js +23 -1
- package/lib/engine-components/web/Clickthrough.js.map +1 -1
- package/lib/engine-components/web/ScrollFollow.d.ts +4 -9
- package/lib/engine-components/web/ScrollFollow.js +26 -30
- package/lib/engine-components/web/ScrollFollow.js.map +1 -1
- package/lib/engine-components/web/ViewBox.d.ts +16 -0
- package/lib/engine-components/web/ViewBox.js +35 -3
- package/lib/engine-components/web/ViewBox.js.map +1 -1
- package/package.json +1 -1
- package/src/engine/engine_physics.ts +3 -3
- package/src/engine-components/OrbitControls.ts +5 -2
- package/src/engine-components/splines/SplineWalker.ts +99 -14
- package/src/engine-components/web/Clickthrough.ts +28 -1
- package/src/engine-components/web/ScrollFollow.ts +31 -33
- package/src/engine-components/web/ViewBox.ts +35 -5
|
@@ -37,24 +37,47 @@ const disabledGizmoColor = new RGBAColor(.5, .5, .5, .5);
|
|
|
37
37
|
* @component
|
|
38
38
|
*/
|
|
39
39
|
let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
40
|
+
/**
|
|
41
|
+
* All active ViewBox instances. The last one in the array is the currently active one.
|
|
42
|
+
*/
|
|
40
43
|
static instances = [];
|
|
41
44
|
/**
|
|
42
45
|
* The reference field of view is used to calculate the box size. This should usually be the same as your camera's fov.
|
|
43
46
|
* @default -1 (meaning it will use the camera fov on the first frame)
|
|
44
47
|
*/
|
|
45
48
|
referenceFieldOfView = -1;
|
|
49
|
+
/**
|
|
50
|
+
* The mode determines if the viewbox should be applied once or continuously while it is the active viewbox.
|
|
51
|
+
* Options:
|
|
52
|
+
* - "once": The viewbox will be applied once when it becomes the active viewbox. This is useful if you want to fit the view once and then allow the user to zoom or pan freely.
|
|
53
|
+
* - "continuous": The viewbox will be applied continuously while it is the active viewbox. This is useful if you animate or scale the viewbox over time.
|
|
54
|
+
*/
|
|
55
|
+
get mode() { return this._mode; }
|
|
56
|
+
set mode(v) {
|
|
57
|
+
if (v === this._mode)
|
|
58
|
+
return;
|
|
59
|
+
this._mode = v;
|
|
60
|
+
if (v === "once")
|
|
61
|
+
this._applyCount = 0;
|
|
62
|
+
if (debugParam || this.debug)
|
|
63
|
+
console.debug("[ViewBox] Set mode:", v);
|
|
64
|
+
}
|
|
65
|
+
_mode = "continuous";
|
|
46
66
|
/**
|
|
47
67
|
* Enable debug logs and rendering for this component instance
|
|
48
68
|
*/
|
|
49
69
|
debug = false;
|
|
70
|
+
/** @internal */
|
|
50
71
|
onEnable() {
|
|
51
72
|
if (debugParam || this.debug || isDevEnvironment())
|
|
52
73
|
console.debug("[ViewBox] Using camera fov:", this.referenceFieldOfView);
|
|
53
74
|
// register instance
|
|
54
75
|
ViewBox_1.instances.push(this);
|
|
76
|
+
this._applyCount = 0;
|
|
55
77
|
this.removeUpdateCallback();
|
|
56
78
|
this.context.pre_render_callbacks.push(this.internalUpdate);
|
|
57
79
|
}
|
|
80
|
+
/** @internal */
|
|
58
81
|
onDisable() {
|
|
59
82
|
if (debugParam || this.debug)
|
|
60
83
|
console.debug("[ViewBox] Disabled");
|
|
@@ -73,6 +96,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
73
96
|
}
|
|
74
97
|
static _tempProjectionMatrix = new Matrix4();
|
|
75
98
|
static _tempProjectionMatrixInverse = new Matrix4();
|
|
99
|
+
_applyCount = 0;
|
|
76
100
|
internalUpdate = () => {
|
|
77
101
|
if (this.context.isInXR)
|
|
78
102
|
return;
|
|
@@ -104,6 +128,10 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
104
128
|
console.warn("[ViewBox] No valid referenceFieldOfView set, cannot adjust box size:", this.referenceFieldOfView);
|
|
105
129
|
return;
|
|
106
130
|
}
|
|
131
|
+
if (this._applyCount >= 1 && this.mode === "once") {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this._applyCount++;
|
|
107
135
|
const domWidth = this.context.domWidth;
|
|
108
136
|
const domHeight = this.context.domHeight;
|
|
109
137
|
let rectWidth = domWidth;
|
|
@@ -122,7 +150,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
122
150
|
ViewBox_1._tempProjectionMatrix.copy(camera.projectionMatrix);
|
|
123
151
|
ViewBox_1._tempProjectionMatrixInverse.copy(camera.projectionMatrixInverse);
|
|
124
152
|
const view = camera.view;
|
|
125
|
-
const
|
|
153
|
+
const cameraZoom = camera.zoom;
|
|
126
154
|
const aspect = camera.aspect;
|
|
127
155
|
const fov = camera.fov;
|
|
128
156
|
// Set values to default so we can calculate the box size correctly
|
|
@@ -173,6 +201,7 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
173
201
|
const boxWidth = (projectedBox.maxX - projectedBox.minX);
|
|
174
202
|
const boxHeight = (projectedBox.maxY - projectedBox.minY);
|
|
175
203
|
const scale = this.fit(boxWidth * camera.aspect, boxHeight, width / diffWidth, height / diffHeight);
|
|
204
|
+
const zoom = scale / (height * .5);
|
|
176
205
|
// console.log({ scale, width, height, boxWidth: boxWidth * camera.aspect, boxHeight, diffWidth, diffHeight, aspect: camera.aspect, distance })
|
|
177
206
|
// this.context.focusRectSettings.zoom = 1.39;
|
|
178
207
|
// if (!this.context.focusRect) this.context.setCameraFocusRect(this.context.domElement);
|
|
@@ -181,13 +210,13 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
181
210
|
vec.project(camera);
|
|
182
211
|
this.context.focusRectSettings.offsetX = vec.x;
|
|
183
212
|
this.context.focusRectSettings.offsetY = vec.y;
|
|
184
|
-
this.context.focusRectSettings.zoom =
|
|
213
|
+
this.context.focusRectSettings.zoom = zoom;
|
|
185
214
|
// if we don't have a focus rect yet, set it to the dom element
|
|
186
215
|
if (!this.context.focusRect)
|
|
187
216
|
this.context.setCameraFocusRect(this.context.domElement);
|
|
188
217
|
// Reset values
|
|
189
218
|
camera.view = view;
|
|
190
|
-
camera.zoom =
|
|
219
|
+
camera.zoom = cameraZoom;
|
|
191
220
|
camera.aspect = aspect;
|
|
192
221
|
camera.fov = fov;
|
|
193
222
|
camera.projectionMatrix.copy(ViewBox_1._tempProjectionMatrix);
|
|
@@ -259,6 +288,9 @@ let ViewBox = ViewBox_1 = class ViewBox extends Behaviour {
|
|
|
259
288
|
__decorate([
|
|
260
289
|
serializable()
|
|
261
290
|
], ViewBox.prototype, "referenceFieldOfView", void 0);
|
|
291
|
+
__decorate([
|
|
292
|
+
serializable()
|
|
293
|
+
], ViewBox.prototype, "mode", null);
|
|
262
294
|
__decorate([
|
|
263
295
|
serializable()
|
|
264
296
|
], ViewBox.prototype, "debug", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewBox.js","sourceRoot":"","sources":["../../../src/engine-components/web/ViewBox.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAU,OAAO,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ViewBox.js","sourceRoot":"","sources":["../../../src/engine-components/web/ViewBox.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/engine",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.1",
|
|
4
4
|
"description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
|
|
5
5
|
"main": "dist/needle-engine.min.js",
|
|
6
6
|
"exports": {
|
|
@@ -323,7 +323,7 @@ export class Physics {
|
|
|
323
323
|
|
|
324
324
|
let shouldIntersectObject = true;
|
|
325
325
|
const mesh = obj as Mesh | SkinnedMesh;
|
|
326
|
-
const geo = mesh.geometry;
|
|
326
|
+
const geo = mesh.geometry as BufferGeometry | null | undefined;
|
|
327
327
|
|
|
328
328
|
if (obj.raycastAllowed === false) {
|
|
329
329
|
shouldIntersectObject = false;
|
|
@@ -356,7 +356,7 @@ export class Physics {
|
|
|
356
356
|
|
|
357
357
|
let usePrecise = preference !== "bounds";
|
|
358
358
|
if (options.precise === false) usePrecise = false;
|
|
359
|
-
usePrecise ||= geo.getAttribute("position")?.array?.length < 64;
|
|
359
|
+
if (geo) usePrecise ||= geo.getAttribute("position")?.array?.length < 64;
|
|
360
360
|
if (mesh instanceof GroundedSkybox) {
|
|
361
361
|
usePrecise = false;
|
|
362
362
|
}
|
|
@@ -379,7 +379,7 @@ export class Physics {
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
// Restore
|
|
382
|
-
mesh.geometry = geo;
|
|
382
|
+
mesh.geometry = geo as any;
|
|
383
383
|
|
|
384
384
|
// Debug
|
|
385
385
|
if (debugPhysics && results.length != lastResultsCount) {
|
|
@@ -711,8 +711,10 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
711
711
|
|
|
712
712
|
|
|
713
713
|
if (this._controls) {
|
|
714
|
-
if (this.debugLog)
|
|
715
|
-
|
|
714
|
+
if (this.debugLog) this._controls.domElement = this.context.renderer.domElement;
|
|
715
|
+
|
|
716
|
+
const viewZoomFactor = 1 / (this.context.focusRectSettings?.zoom || 1);
|
|
717
|
+
|
|
716
718
|
this._controls.enabled = !this._shouldDisable && this._camera === this.context.mainCameraComponent && !this.context.isInXR && !this._activePointerEvents.some(e => e.used);
|
|
717
719
|
this._controls.keys = this.enableKeys ? defaultKeys : disabledKeys;
|
|
718
720
|
this._controls.autoRotate = this.autoRotate;
|
|
@@ -723,6 +725,7 @@ export class OrbitControls extends Behaviour implements ICameraController {
|
|
|
723
725
|
this._controls.enableDamping = this.enableDamping;
|
|
724
726
|
this._controls.dampingFactor = this.dampingFactor;
|
|
725
727
|
this._controls.enablePan = this.enablePan;
|
|
728
|
+
this._controls.panSpeed = viewZoomFactor;
|
|
726
729
|
this._controls.enableRotate = this.enableRotate;
|
|
727
730
|
this._controls.minAzimuthAngle = this.minAzimuthAngle;
|
|
728
731
|
this._controls.maxAzimuthAngle = this.maxAzimuthAngle;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { Object3D } from "three"
|
|
2
|
+
import { Object3D, Vector3 } from "three"
|
|
3
3
|
|
|
4
4
|
import { Mathf } from "../../engine/engine_math.js";
|
|
5
5
|
import { serializeable } from "../../engine/engine_serialization_decorator.js";
|
|
@@ -7,7 +7,10 @@ import { Behaviour } from "../Component.js";
|
|
|
7
7
|
import { SplineContainer } from "./Spline.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Moves an object along a spline.
|
|
10
|
+
* Moves an object along a spline.
|
|
11
|
+
* Use this with a SplineContainer component.
|
|
12
|
+
*
|
|
13
|
+
* - Example http://samples.needle.tools/splines
|
|
11
14
|
*/
|
|
12
15
|
export class SplineWalker extends Behaviour {
|
|
13
16
|
|
|
@@ -17,18 +20,35 @@ export class SplineWalker extends Behaviour {
|
|
|
17
20
|
@serializeable(SplineContainer)
|
|
18
21
|
spline: SplineContainer | null = null;
|
|
19
22
|
|
|
20
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* The object to move along the spline.
|
|
25
|
+
* If object is undefined then the spline walker will use it's own object (gameObject).
|
|
26
|
+
* If object is null the spline walker will not move any object.
|
|
21
27
|
* @default undefined
|
|
22
28
|
*/
|
|
23
29
|
@serializeable(Object3D)
|
|
24
30
|
object?: Object3D | null = undefined;
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* If true the object will rotate to look in the direction of the spline while moving along it.
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
@serializeable()
|
|
39
|
+
useLookAt = true;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The object to look at while moving along the spline.
|
|
43
|
+
* If null the object will look in the direction of the spline.
|
|
44
|
+
* This can be disabled by setting useLookAt to false.
|
|
27
45
|
* @default null
|
|
28
46
|
*/
|
|
29
47
|
@serializeable(Object3D)
|
|
30
48
|
lookAt: Object3D | null = null;
|
|
31
|
-
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
32
52
|
/**
|
|
33
53
|
* When clamp is set to true, the position01 value will be clamped between 0 and 1 and the object will not loop the spline.
|
|
34
54
|
* @default false
|
|
@@ -36,7 +56,10 @@ export class SplineWalker extends Behaviour {
|
|
|
36
56
|
@serializeable()
|
|
37
57
|
clamp: boolean = false;
|
|
38
58
|
|
|
39
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* The current position on the spline. The value ranges from 0 (start of the spline curve) to 1 (end of the spline curve)
|
|
61
|
+
*
|
|
62
|
+
* When setting this value, the position will be updated in the next frame.
|
|
40
63
|
* @default 0
|
|
41
64
|
*/
|
|
42
65
|
// @type float
|
|
@@ -46,7 +69,7 @@ export class SplineWalker extends Behaviour {
|
|
|
46
69
|
}
|
|
47
70
|
set position01(v: number) {
|
|
48
71
|
this._position01 = v;
|
|
49
|
-
this.
|
|
72
|
+
this._needsUpdate = true;
|
|
50
73
|
}
|
|
51
74
|
|
|
52
75
|
/** Resets the position to 0 */
|
|
@@ -68,25 +91,60 @@ export class SplineWalker extends Behaviour {
|
|
|
68
91
|
@serializeable()
|
|
69
92
|
duration: number = 10;
|
|
70
93
|
|
|
94
|
+
/**
|
|
95
|
+
* The strength with which the object is pulled to the spline.
|
|
96
|
+
* This can be used to create a "rubber band" effect when the object is moved away from the spline by other forces.
|
|
97
|
+
* A value of 0 means no pull, a value of 1 means the object is always on the spline.
|
|
98
|
+
* @default 1
|
|
99
|
+
*/
|
|
100
|
+
pullStrength: number = 1;
|
|
101
|
+
|
|
71
102
|
|
|
72
103
|
// #region internal
|
|
73
104
|
|
|
74
105
|
private _position01: number = 0;
|
|
106
|
+
private _needsUpdate = false;
|
|
75
107
|
|
|
76
108
|
/** @internal */
|
|
77
109
|
start() {
|
|
78
|
-
if(this.object === undefined) this.object = this.gameObject;
|
|
110
|
+
if (this.object === undefined) this.object = this.gameObject;
|
|
79
111
|
this.updateFromPosition();
|
|
80
112
|
}
|
|
81
113
|
|
|
114
|
+
/** @internal */
|
|
115
|
+
onEnable(): void {
|
|
116
|
+
window.addEventListener("pointerdown", this.onUserInput, { passive: true });
|
|
117
|
+
window.addEventListener("wheel", this.onUserInput, { passive: true });
|
|
118
|
+
}
|
|
119
|
+
/** @internal */
|
|
120
|
+
onDisable(): void {
|
|
121
|
+
window.removeEventListener("pointerdown", this.onUserInput);
|
|
122
|
+
window.removeEventListener("wheel", this.onUserInput);
|
|
123
|
+
}
|
|
124
|
+
private onUserInput = () => {
|
|
125
|
+
if (this.object?.contains(this.context.mainCamera)) {
|
|
126
|
+
this._needsUpdate = false;
|
|
127
|
+
this._performedUpdates += 999;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @internal */
|
|
82
132
|
update() {
|
|
83
133
|
if (this.autoRun) {
|
|
134
|
+
this._needsUpdate = true;
|
|
84
135
|
this._position01 += this.context.time.deltaTime / this.duration;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (this._needsUpdate) {
|
|
139
|
+
this._needsUpdate = false;
|
|
85
140
|
this.updateFromPosition();
|
|
86
141
|
}
|
|
87
142
|
}
|
|
88
143
|
|
|
89
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Updates the position of the object based on the current position01 value.
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
90
148
|
private updateFromPosition() {
|
|
91
149
|
if (!this.spline || !this.spline.curve) return;
|
|
92
150
|
if (!this.object) return;
|
|
@@ -96,11 +154,38 @@ export class SplineWalker extends Behaviour {
|
|
|
96
154
|
|
|
97
155
|
const t = this._position01 >= 1 ? 1 : this._position01 % 1;
|
|
98
156
|
const pt = this.spline.getPointAt(t);
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
157
|
+
|
|
158
|
+
if (this.pullStrength >= 1) {
|
|
159
|
+
this.object.worldPosition = pt;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
if (this._position01 !== this._lastPosition01) {
|
|
163
|
+
this._performedUpdates = 0;
|
|
164
|
+
}
|
|
165
|
+
this._requiredUpdates = Math.round(100 / this.pullStrength);
|
|
166
|
+
if (this._performedUpdates < this._requiredUpdates) {
|
|
167
|
+
const wp = this.object.worldPosition;
|
|
168
|
+
this._performedUpdates++;
|
|
169
|
+
const pull = Mathf.clamp01(this.pullStrength);
|
|
170
|
+
const newPosition = this.object.worldPosition = wp.lerp(pt, pull * (this.context.time.deltaTime / .3));
|
|
171
|
+
this._lastPositionVector.copy(newPosition);
|
|
172
|
+
this._needsUpdate = true;
|
|
173
|
+
}
|
|
103
174
|
}
|
|
104
|
-
|
|
175
|
+
|
|
176
|
+
if (this.useLookAt) {
|
|
177
|
+
if (!this.lookAt) {
|
|
178
|
+
const tan = this.spline.getTangentAt(t);
|
|
179
|
+
this.object.lookAt(pt.add(tan));
|
|
180
|
+
}
|
|
181
|
+
else this.object.lookAt(this.lookAt.worldPosition);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this._lastPosition01 = this._position01;
|
|
105
185
|
}
|
|
186
|
+
|
|
187
|
+
private _lastPosition01 = 0;
|
|
188
|
+
private _requiredUpdates: number = 0;
|
|
189
|
+
private _performedUpdates: number = 0;
|
|
190
|
+
private _lastPositionVector = new Vector3();
|
|
106
191
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Vector2 } from "three";
|
|
1
2
|
import { NEPointerEvent } from "../../engine/engine_input.js";
|
|
2
3
|
import { onStart } from "../../engine/engine_lifecycle_api.js";
|
|
3
4
|
import { addAttributeChangeCallback } from "../../engine/engine_utils.js";
|
|
@@ -45,12 +46,14 @@ export class ClickThrough extends Behaviour {
|
|
|
45
46
|
this.context.input.addEventListener('pointermove', this.onPointerEvent, {
|
|
46
47
|
queue: 100,
|
|
47
48
|
});
|
|
49
|
+
window.addEventListener("touchstart", this.onTouchStart, { passive: true });
|
|
48
50
|
window.addEventListener("touchend", this.onTouchEnd, { passive: true });
|
|
49
51
|
this._previousPointerEvents = this.context.domElement.style.pointerEvents;
|
|
50
52
|
}
|
|
51
53
|
onDisable() {
|
|
52
54
|
this.context.input.removeEventListener('pointerdown', this.onPointerEvent);
|
|
53
55
|
this.context.input.removeEventListener('pointermove', this.onPointerEvent);
|
|
56
|
+
window.removeEventListener("touchstart", this.onTouchStart);
|
|
54
57
|
window.removeEventListener("touchend", this.onTouchEnd);
|
|
55
58
|
this.context.domElement.style.pointerEvents = this._previousPointerEvents;
|
|
56
59
|
}
|
|
@@ -69,9 +72,33 @@ export class ClickThrough extends Behaviour {
|
|
|
69
72
|
}
|
|
70
73
|
};
|
|
71
74
|
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
// #region Touch hack
|
|
78
|
+
|
|
79
|
+
private _touchDidHitAnything = false;
|
|
80
|
+
|
|
81
|
+
private onTouchStart = (_evt: TouchEvent) => {
|
|
82
|
+
|
|
83
|
+
const touch = _evt.touches[0];
|
|
84
|
+
if (!touch) return;
|
|
85
|
+
|
|
86
|
+
const ndx = touch.clientX / window.innerWidth * 2 - 1;
|
|
87
|
+
const ndy = -(touch.clientY / window.innerHeight) * 2 + 1;
|
|
88
|
+
// console.log(ndx, ndy);
|
|
89
|
+
const hits = this.context.physics.raycast({
|
|
90
|
+
screenPoint: new Vector2(ndx, ndy),
|
|
91
|
+
})
|
|
92
|
+
if (hits.length > 0) {
|
|
93
|
+
this._touchDidHitAnything = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
72
97
|
private onTouchEnd = (_evt: TouchEvent) => {
|
|
98
|
+
const _didHit = this._touchDidHitAnything;
|
|
99
|
+
this._touchDidHitAnything = false;
|
|
73
100
|
setTimeout(() => {
|
|
74
|
-
this.context.domElement.style.pointerEvents = 'all';
|
|
101
|
+
if (_didHit) this.context.domElement.style.pointerEvents = 'all';
|
|
75
102
|
}, 100);
|
|
76
103
|
}
|
|
77
104
|
}
|
|
@@ -96,6 +96,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
96
96
|
@serializable()
|
|
97
97
|
invert: boolean = false;
|
|
98
98
|
|
|
99
|
+
|
|
99
100
|
/**
|
|
100
101
|
* **Experimental - might change in future updates**
|
|
101
102
|
* If set, the scroll position will be read from the specified element instead of the window.
|
|
@@ -106,7 +107,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
106
107
|
htmlSelector: string | null = null;
|
|
107
108
|
|
|
108
109
|
@serializable()
|
|
109
|
-
|
|
110
|
+
mode: "window" = "window";
|
|
110
111
|
|
|
111
112
|
/**
|
|
112
113
|
* Event fired when the scroll position changes
|
|
@@ -124,17 +125,19 @@ export class ScrollFollow extends Behaviour {
|
|
|
124
125
|
private _current_value: number = 0;
|
|
125
126
|
private _target_value: number = 0;
|
|
126
127
|
private _appliedValue: number = -1;
|
|
128
|
+
private _needsUpdate = false;
|
|
129
|
+
private _firstUpdate = false;
|
|
127
130
|
|
|
131
|
+
awake() {
|
|
132
|
+
this._firstUpdate = true;
|
|
133
|
+
}
|
|
128
134
|
|
|
129
|
-
private _scrollStart: number = 0;
|
|
130
|
-
private _scrollEnd: number = 0;
|
|
131
|
-
private _scrollValue: number = 0;
|
|
132
|
-
private _scrollContainerHeight: number = 0;
|
|
133
135
|
|
|
134
136
|
/** @internal */
|
|
135
137
|
onEnable() {
|
|
136
138
|
window.addEventListener("wheel", this.updateCurrentScrollValue, { passive: true });
|
|
137
139
|
this._appliedValue = -1;
|
|
140
|
+
this._needsUpdate = true;
|
|
138
141
|
}
|
|
139
142
|
|
|
140
143
|
/** @internal */
|
|
@@ -148,7 +151,7 @@ export class ScrollFollow extends Behaviour {
|
|
|
148
151
|
this.updateCurrentScrollValue();
|
|
149
152
|
|
|
150
153
|
if (this._target_value >= 0) {
|
|
151
|
-
if (this.damping > 0) { // apply damping
|
|
154
|
+
if (this.damping > 0 && !this._firstUpdate) { // apply damping
|
|
152
155
|
this._current_value = Mathf.lerp(this._current_value, this._target_value, this.context.time.deltaTime / this.damping);
|
|
153
156
|
if (Math.abs(this._current_value - this._target_value) < 0.001) {
|
|
154
157
|
this._current_value = this._target_value;
|
|
@@ -159,9 +162,10 @@ export class ScrollFollow extends Behaviour {
|
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
|
|
162
|
-
|
|
165
|
+
if (this._needsUpdate || this._current_value !== this._appliedValue)
|
|
163
166
|
{
|
|
164
167
|
this._appliedValue = this._current_value;
|
|
168
|
+
this._needsUpdate = false;
|
|
165
169
|
|
|
166
170
|
let defaultPrevented = false;
|
|
167
171
|
if (this.changed.listenerCount > 0) {
|
|
@@ -182,9 +186,6 @@ export class ScrollFollow extends Behaviour {
|
|
|
182
186
|
|
|
183
187
|
const value = this.invert ? 1 - this._current_value : this._current_value;
|
|
184
188
|
|
|
185
|
-
// const height = this._rangeEndValue - this._rangeStartValue;
|
|
186
|
-
// const pixelValue = this._rangeStartValue + value * height;
|
|
187
|
-
|
|
188
189
|
// apply scroll to target(s)
|
|
189
190
|
if (Array.isArray(this.target)) {
|
|
190
191
|
this.target.forEach(t => t && this.applyScroll(t, value));
|
|
@@ -197,21 +198,18 @@ export class ScrollFollow extends Behaviour {
|
|
|
197
198
|
console.debug(`[ScrollFollow] ${this._current_value.toFixed(5)} — ${(this._target_value * 100).toFixed(0)}%, targets [${Array.isArray(this.target) ? this.target.length : 1}]`);
|
|
198
199
|
}
|
|
199
200
|
}
|
|
201
|
+
|
|
202
|
+
this._firstUpdate = false;
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
private _lastSelectorValue: string | null = null;
|
|
204
207
|
private _lastSelectorElement: Element | null = null;
|
|
205
|
-
/** Top y */
|
|
206
|
-
private _rangeStartValue: number = 0;
|
|
207
|
-
/** Bottom y */
|
|
208
|
-
private _rangeEndValue: number = 0;
|
|
209
208
|
|
|
210
209
|
private updateCurrentScrollValue = () => {
|
|
211
210
|
|
|
212
211
|
switch (this.mode) {
|
|
213
212
|
case "window":
|
|
214
|
-
|
|
215
213
|
if (this.htmlSelector?.length) {
|
|
216
214
|
if (this.htmlSelector !== this._lastSelectorValue) {
|
|
217
215
|
this._lastSelectorElement = document.querySelector(this.htmlSelector);
|
|
@@ -219,26 +217,20 @@ export class ScrollFollow extends Behaviour {
|
|
|
219
217
|
}
|
|
220
218
|
if (this._lastSelectorElement) {
|
|
221
219
|
const rect = this._lastSelectorElement.getBoundingClientRect();
|
|
222
|
-
|
|
223
|
-
this._scrollStart = rect.top + window.scrollY;
|
|
224
|
-
this._scrollEnd = rect.height - window.innerHeight;
|
|
225
|
-
this._scrollValue = -rect.top;
|
|
226
220
|
this._target_value = -rect.top / (rect.height - window.innerHeight);
|
|
227
|
-
this._rangeStartValue = rect.top + window.scrollY;
|
|
228
|
-
this._rangeEndValue = this._rangeStartValue + rect.height - window.innerHeight;
|
|
229
|
-
this._scrollContainerHeight = rect.height;
|
|
230
221
|
break;
|
|
231
222
|
}
|
|
232
223
|
}
|
|
233
224
|
else {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
225
|
+
if (window.document.body.scrollHeight <= window.innerHeight) {
|
|
226
|
+
// If the page is not scrollable we can still increment the scroll value to allow triggering timelines etc.
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const diff = window.document.body.scrollHeight - window.innerHeight;
|
|
230
|
+
this._target_value = window.scrollY / (diff || 1);
|
|
231
|
+
}
|
|
241
232
|
}
|
|
233
|
+
|
|
242
234
|
break;
|
|
243
235
|
}
|
|
244
236
|
|
|
@@ -272,11 +264,12 @@ export class ScrollFollow extends Behaviour {
|
|
|
272
264
|
target.intensity = value;
|
|
273
265
|
}
|
|
274
266
|
else if (target instanceof Object3D) {
|
|
267
|
+
const t = target as any;
|
|
275
268
|
// When objects are assigned they're expected to move vertically based on scroll
|
|
276
|
-
if (
|
|
277
|
-
|
|
269
|
+
if (t["needle:scrollbounds"] === undefined) {
|
|
270
|
+
t["needle:scrollbounds"] = getBoundingBox(target) || null;
|
|
278
271
|
}
|
|
279
|
-
const bounds =
|
|
272
|
+
const bounds = t["needle:scrollbounds"] as Box3;
|
|
280
273
|
if (bounds) {
|
|
281
274
|
// TODO: remap position to use upper screen edge and lower edge instead of center
|
|
282
275
|
target.position.y = -bounds.min.y - value * (bounds.max.y - bounds.min.y);
|
|
@@ -422,13 +415,18 @@ export class ScrollFollow extends Behaviour {
|
|
|
422
415
|
time += diff * weight;
|
|
423
416
|
}
|
|
424
417
|
}
|
|
425
|
-
if (this.damping <= 0) {
|
|
418
|
+
if (this.damping <= 0 || this._firstUpdate) {
|
|
426
419
|
director.time = time;
|
|
427
420
|
}
|
|
428
421
|
else {
|
|
429
422
|
director.time = Mathf.lerp(director.time, time, this.context.time.deltaTime / this.damping);
|
|
430
423
|
}
|
|
431
424
|
|
|
425
|
+
const delta = Math.abs(director.time - time);
|
|
426
|
+
if (delta > .001) { // if the time is > 1/100th of a second off we need another update
|
|
427
|
+
this._needsUpdate = true;
|
|
428
|
+
}
|
|
429
|
+
|
|
432
430
|
if (debug && this.context.time.frame % 30 === 0) {
|
|
433
431
|
console.log(`[ScrollFollow ] Timeline ${director.name}: ${time.toFixed(3)}`, weightsArray.map(w => `[${w.name} ${(w.weight * 100).toFixed(0)}%]`).join(", "));
|
|
434
432
|
}
|