@shopware-ag/dive 1.16.24 → 1.16.26-beta.0
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/build/dive.cjs +1652 -203
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +50 -8
- package/build/dive.d.ts +50 -8
- package/build/dive.js +1619 -159
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/ar/AR.ts +164 -0
- package/src/ar/arquicklook/ARQuickLook.ts +42 -0
- package/src/ar/webxr/WebXR.ts +176 -0
- package/src/ar/webxr/controller/WebXRController.ts +334 -0
- package/src/ar/webxr/crosshair/WebXRCrosshair.ts +35 -0
- package/src/ar/webxr/origin/WebXROrigin.ts +191 -0
- package/src/ar/webxr/overlay/Overlay.ts +50 -0
- package/src/ar/webxr/raycaster/WebXRRaycaster.ts +131 -0
- package/src/ar/webxr/raycaster/ar/WebXRRaycasterAR.ts +102 -0
- package/src/ar/webxr/raycaster/three/WebXRRaycasterTHREE.ts +49 -0
- package/src/ar/webxr/touchscreencontrols/WebXRTouchscreenControls.ts +356 -0
- package/src/axiscamera/AxisCamera.ts +4 -4
- package/src/axiscamera/__test__/AxisCamera.test.ts +4 -0
- package/src/com/Communication.ts +17 -0
- package/src/com/__test__/Communication.test.ts +1 -1
- package/src/com/actions/index.ts +2 -0
- package/src/dive.ts +51 -9
- package/src/events/EventExecutor.ts +35 -0
- package/src/helper/findSceneRecursive/findSceneRecursive.ts +2 -2
- package/src/info/Info.ts +37 -1
- package/src/info/__test__/Info.test.ts +45 -5
- package/src/mediacreator/MediaCreator.ts +4 -4
- package/src/mediacreator/__test__/MediaCreator.test.ts +7 -2
- package/src/renderer/Renderer.ts +21 -11
- package/src/renderer/__test__/Renderer.test.ts +19 -1
- package/src/scene/Scene.ts +35 -12
- package/src/scene/__test__/Scene.test.ts +39 -5
- package/src/scene/root/Root.ts +1 -0
- package/src/scene/xrroot/XRRoot.ts +56 -0
- package/src/scene/xrroot/xrlightroot/XRLightRoot.ts +80 -0
- package/src/toolbox/BaseTool.ts +9 -3
- package/src/toolbox/Toolbox.ts +1 -1
- package/src/toolbox/__test__/Toolbox.test.ts +1 -1
- package/src/toolbox/select/SelectTool.ts +1 -1
- package/src/toolbox/select/__test__/SelectTool.test.ts +1 -1
- package/src/toolbox/transform/TransformTool.ts +4 -4
- package/src/toolbox/transform/__test__/TransformTool.test.ts +2 -4
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Matrix4, Mesh, Vector3 } from 'three';
|
|
2
|
+
import { DIVERenderer } from '../../../renderer/Renderer';
|
|
3
|
+
import { DIVEWebXRRaycasterAR } from './ar/WebXRRaycasterAR';
|
|
4
|
+
import { DIVEWebXRRaycasterTHREE } from './three/WebXRRaycasterTHREE';
|
|
5
|
+
import { DIVEScene } from '../../../scene/Scene';
|
|
6
|
+
import { DIVEEventExecutor } from '../../../events/EventExecutor';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* object is undefined when AR world is hit.
|
|
10
|
+
*/
|
|
11
|
+
export type DIVEHitResult = {
|
|
12
|
+
point: Vector3;
|
|
13
|
+
matrix: Matrix4;
|
|
14
|
+
object?: Mesh;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type DIVEWebXRRaycasterEvents = {
|
|
18
|
+
AR_HIT_FOUND: {
|
|
19
|
+
hit: DIVEHitResult;
|
|
20
|
+
};
|
|
21
|
+
AR_HIT_LOST: undefined;
|
|
22
|
+
SCENE_HIT_FOUND: {
|
|
23
|
+
hit: DIVEHitResult;
|
|
24
|
+
};
|
|
25
|
+
SCENE_HIT_LOST: undefined;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export class DIVEWebXRRaycaster extends DIVEEventExecutor<DIVEWebXRRaycasterEvents> {
|
|
29
|
+
private _session: XRSession;
|
|
30
|
+
|
|
31
|
+
private _initialized: boolean = false;
|
|
32
|
+
|
|
33
|
+
private _threeRaycaster: DIVEWebXRRaycasterTHREE;
|
|
34
|
+
private _arRaycaster: DIVEWebXRRaycasterAR;
|
|
35
|
+
|
|
36
|
+
private _arHitResultBuffer: DIVEHitResult[] = [];
|
|
37
|
+
private _sceneHitResultBuffer: DIVEHitResult[] = [];
|
|
38
|
+
|
|
39
|
+
// buffers
|
|
40
|
+
private _hasHit: boolean = false;
|
|
41
|
+
|
|
42
|
+
constructor(session: XRSession, renderer: DIVERenderer, scene: DIVEScene) {
|
|
43
|
+
super();
|
|
44
|
+
|
|
45
|
+
this._session = session;
|
|
46
|
+
|
|
47
|
+
this._threeRaycaster = new DIVEWebXRRaycasterTHREE(renderer, scene);
|
|
48
|
+
this._arRaycaster = new DIVEWebXRRaycasterAR(session, renderer);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public Dispose(): void {
|
|
52
|
+
// dispose code here
|
|
53
|
+
this._initialized = false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public async Init(): Promise<this> {
|
|
57
|
+
if (!this._session) {
|
|
58
|
+
console.error(
|
|
59
|
+
'DIVEWebXRRaycaster: No session set in Init()! Aborting initialization...',
|
|
60
|
+
);
|
|
61
|
+
return Promise.reject();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this._initialized) {
|
|
65
|
+
console.error(
|
|
66
|
+
'DIVEWebXRRaycaster: Already initialized! Aborting initialization...',
|
|
67
|
+
);
|
|
68
|
+
return Promise.reject();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await this._threeRaycaster.Init();
|
|
72
|
+
await this._arRaycaster.Init();
|
|
73
|
+
|
|
74
|
+
console.log('DIVEWebXRRaycaster: Initialized');
|
|
75
|
+
|
|
76
|
+
this._initialized = true;
|
|
77
|
+
|
|
78
|
+
return Promise.resolve(this);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public GetARIntersections(frame: XRFrame): DIVEHitResult[] {
|
|
82
|
+
// check for ar hits
|
|
83
|
+
this._arHitResultBuffer = this._arRaycaster.GetIntersections(frame);
|
|
84
|
+
if (this._arHitResultBuffer.length > 0) {
|
|
85
|
+
// hit found
|
|
86
|
+
this.onARHitFound(this._arHitResultBuffer[0]);
|
|
87
|
+
} else {
|
|
88
|
+
// hit nothing
|
|
89
|
+
this.onARHitLost();
|
|
90
|
+
}
|
|
91
|
+
return this._arHitResultBuffer;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public GetSceneIntersections(): DIVEHitResult[] {
|
|
95
|
+
// check for scene hits
|
|
96
|
+
this._sceneHitResultBuffer = this._threeRaycaster.GetIntersections();
|
|
97
|
+
if (this._sceneHitResultBuffer.length > 0) {
|
|
98
|
+
// scene hit found
|
|
99
|
+
this.onSceneHitFound(this._sceneHitResultBuffer[0]);
|
|
100
|
+
// early return to prevent ar raycaster from overriding scene hit
|
|
101
|
+
} else {
|
|
102
|
+
// scene hit nothing
|
|
103
|
+
this.onSceneHitLost();
|
|
104
|
+
}
|
|
105
|
+
return this._sceneHitResultBuffer;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private onARHitFound(hit: DIVEHitResult): void {
|
|
109
|
+
this._hasHit = true;
|
|
110
|
+
this.dispatch('AR_HIT_FOUND', { hit });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private onARHitLost(): void {
|
|
114
|
+
if (!this._hasHit) return;
|
|
115
|
+
|
|
116
|
+
this._hasHit = false;
|
|
117
|
+
this.dispatch('AR_HIT_LOST');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private onSceneHitFound(hit: DIVEHitResult): void {
|
|
121
|
+
this._hasHit = true;
|
|
122
|
+
this.dispatch('SCENE_HIT_FOUND', { hit });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private onSceneHitLost(): void {
|
|
126
|
+
if (!this._hasHit) return;
|
|
127
|
+
|
|
128
|
+
this._hasHit = false;
|
|
129
|
+
this.dispatch('SCENE_HIT_LOST');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Matrix4, Vector3 } from 'three';
|
|
2
|
+
import { type DIVERenderer } from '../../../../renderer/Renderer';
|
|
3
|
+
import { type DIVEHitResult } from '../WebXRRaycaster';
|
|
4
|
+
|
|
5
|
+
export class DIVEWebXRRaycasterAR {
|
|
6
|
+
private _session: XRSession;
|
|
7
|
+
private _renderer: DIVERenderer;
|
|
8
|
+
|
|
9
|
+
private _transientHitTestSource: XRTransientInputHitTestSource | undefined;
|
|
10
|
+
private _referenceSpaceBuffer: XRReferenceSpace | null = null;
|
|
11
|
+
|
|
12
|
+
private _requesting: boolean = false;
|
|
13
|
+
private _initialized: boolean = false;
|
|
14
|
+
|
|
15
|
+
private _hitMatrixBuffer: Matrix4;
|
|
16
|
+
|
|
17
|
+
constructor(session: XRSession, renderer: DIVERenderer) {
|
|
18
|
+
this._session = session;
|
|
19
|
+
this._renderer = renderer;
|
|
20
|
+
|
|
21
|
+
this._hitMatrixBuffer = new Matrix4();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public Dispose(): void {
|
|
25
|
+
this._transientHitTestSource?.cancel();
|
|
26
|
+
this._transientHitTestSource = undefined;
|
|
27
|
+
|
|
28
|
+
this._initialized = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async Init(): Promise<this> {
|
|
32
|
+
if (!this._session) {
|
|
33
|
+
console.error(
|
|
34
|
+
'DIVEWebXRRaycaster: No session set in Init()! Aborting initialization...',
|
|
35
|
+
);
|
|
36
|
+
return Promise.reject();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (this._requesting) {
|
|
40
|
+
console.error(
|
|
41
|
+
'DIVEWebXRRaycaster: Currently initializing! Aborting initialization...',
|
|
42
|
+
);
|
|
43
|
+
return Promise.reject();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (this._initialized) {
|
|
47
|
+
console.error(
|
|
48
|
+
'DIVEWebXRRaycaster: Already initialized! Aborting initialization...',
|
|
49
|
+
);
|
|
50
|
+
return Promise.reject();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this._requesting = true;
|
|
54
|
+
this._transientHitTestSource = await this._session
|
|
55
|
+
.requestHitTestSourceForTransientInput!({
|
|
56
|
+
profile: 'generic-touchscreen',
|
|
57
|
+
});
|
|
58
|
+
this._referenceSpaceBuffer = this._renderer.xr.getReferenceSpace();
|
|
59
|
+
this._requesting = false;
|
|
60
|
+
|
|
61
|
+
if (!this._transientHitTestSource) {
|
|
62
|
+
return Promise.reject();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this._initialized = true;
|
|
66
|
+
|
|
67
|
+
console.log('DIVEWebXRRaycasterAR: Initialized');
|
|
68
|
+
|
|
69
|
+
return Promise.resolve(this);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public GetIntersections(frame: XRFrame): DIVEHitResult[] {
|
|
73
|
+
if (!this._transientHitTestSource) return [];
|
|
74
|
+
|
|
75
|
+
const touches = frame.getHitTestResultsForTransientInput(
|
|
76
|
+
this._transientHitTestSource,
|
|
77
|
+
);
|
|
78
|
+
if (touches.length === 0) return [];
|
|
79
|
+
|
|
80
|
+
const hits = touches.map((touch: XRTransientInputHitTestResult) => {
|
|
81
|
+
if (!this._referenceSpaceBuffer) return undefined;
|
|
82
|
+
if (!touch.results[0]) return undefined;
|
|
83
|
+
if (!touch.results[0].getPose) return undefined;
|
|
84
|
+
|
|
85
|
+
const pose = touch.results[0].getPose(this._referenceSpaceBuffer);
|
|
86
|
+
if (!pose) return undefined;
|
|
87
|
+
|
|
88
|
+
this._hitMatrixBuffer.fromArray(pose.transform.matrix);
|
|
89
|
+
const position = new Vector3().setFromMatrixPosition(
|
|
90
|
+
this._hitMatrixBuffer,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
point: position,
|
|
95
|
+
matrix: this._hitMatrixBuffer,
|
|
96
|
+
object: undefined,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return hits.filter((hit) => hit !== undefined) as DIVEHitResult[];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Intersection,
|
|
3
|
+
type Mesh,
|
|
4
|
+
Raycaster,
|
|
5
|
+
type XRTargetRaySpace,
|
|
6
|
+
} from 'three';
|
|
7
|
+
import { type DIVERenderer } from '../../../../renderer/Renderer';
|
|
8
|
+
import { type DIVEScene } from '../../../../scene/Scene';
|
|
9
|
+
import { type DIVEHitResult } from '../WebXRRaycaster';
|
|
10
|
+
|
|
11
|
+
export class DIVEWebXRRaycasterTHREE {
|
|
12
|
+
private _renderer: DIVERenderer;
|
|
13
|
+
private _scene: DIVEScene;
|
|
14
|
+
|
|
15
|
+
private _controller: XRTargetRaySpace;
|
|
16
|
+
|
|
17
|
+
// internal raycaster
|
|
18
|
+
private _raycaster: Raycaster = new Raycaster();
|
|
19
|
+
|
|
20
|
+
constructor(renderer: DIVERenderer, scene: DIVEScene) {
|
|
21
|
+
this._renderer = renderer;
|
|
22
|
+
this._scene = scene;
|
|
23
|
+
|
|
24
|
+
this._controller = this._renderer.xr.getController(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public async Init(): Promise<this> {
|
|
28
|
+
console.log('DIVEWebXRRaycasterTHREE: Initialized');
|
|
29
|
+
return Promise.resolve(this);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public GetIntersections(): DIVEHitResult[] {
|
|
33
|
+
this._controller.updateMatrixWorld();
|
|
34
|
+
this._raycaster.setFromXRController(this._controller);
|
|
35
|
+
const intersections = this._raycaster.intersectObjects(
|
|
36
|
+
this._scene.XRRoot.XRModelRoot.children,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (intersections.length === 0) return [];
|
|
40
|
+
|
|
41
|
+
return intersections.map((intersection: Intersection) => {
|
|
42
|
+
return {
|
|
43
|
+
point: intersection.point,
|
|
44
|
+
matrix: intersection.object.matrixWorld,
|
|
45
|
+
object: intersection.object as Mesh,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { Vector2 } from 'three';
|
|
2
|
+
import { DIVEEventExecutor } from '../../../events/EventExecutor';
|
|
3
|
+
|
|
4
|
+
export type DIVETouchscreenEvents = {
|
|
5
|
+
TOUCH_START: {
|
|
6
|
+
touches: {
|
|
7
|
+
current: Vector2;
|
|
8
|
+
}[];
|
|
9
|
+
touchCount: number;
|
|
10
|
+
};
|
|
11
|
+
TOUCH_MOVE: {
|
|
12
|
+
touches: {
|
|
13
|
+
current: Vector2;
|
|
14
|
+
delta: Vector2;
|
|
15
|
+
}[];
|
|
16
|
+
touchCount: number;
|
|
17
|
+
};
|
|
18
|
+
TOUCH_END: {
|
|
19
|
+
touches: {
|
|
20
|
+
current: Vector2;
|
|
21
|
+
}[];
|
|
22
|
+
touchCount: number;
|
|
23
|
+
};
|
|
24
|
+
ROTATE_START: {
|
|
25
|
+
current: number;
|
|
26
|
+
};
|
|
27
|
+
ROTATE_MOVE: {
|
|
28
|
+
current: number;
|
|
29
|
+
delta: number;
|
|
30
|
+
};
|
|
31
|
+
ROTATE_END: {
|
|
32
|
+
current: number;
|
|
33
|
+
};
|
|
34
|
+
PINCH_START: {
|
|
35
|
+
current: number;
|
|
36
|
+
};
|
|
37
|
+
PINCH_MOVE: {
|
|
38
|
+
current: number;
|
|
39
|
+
delta: number;
|
|
40
|
+
};
|
|
41
|
+
PINCH_END: {
|
|
42
|
+
current: number;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type DIVETouch = {
|
|
47
|
+
start: Vector2;
|
|
48
|
+
current: Vector2;
|
|
49
|
+
delta: Vector2;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export class DIVEWebXRTouchscreenControls extends DIVEEventExecutor<DIVETouchscreenEvents> {
|
|
53
|
+
// general members
|
|
54
|
+
private _session: XRSession;
|
|
55
|
+
|
|
56
|
+
// touch members
|
|
57
|
+
private _touchCount: number = 0;
|
|
58
|
+
private _touches: DIVETouch[] = [];
|
|
59
|
+
|
|
60
|
+
// rotate members
|
|
61
|
+
private _handleRotateStarted: boolean = false;
|
|
62
|
+
private _handleRotateMoved: boolean = false;
|
|
63
|
+
private _handleRotateEnded: boolean = false;
|
|
64
|
+
|
|
65
|
+
private _startAngle: number = 0;
|
|
66
|
+
private _lastAngle: number = 0;
|
|
67
|
+
private _angleDelta: number = 0;
|
|
68
|
+
|
|
69
|
+
// scale members
|
|
70
|
+
private _handlePinchStarted: boolean = false;
|
|
71
|
+
private _handlePinchMoved: boolean = false;
|
|
72
|
+
private _handlePinchEnded: boolean = false;
|
|
73
|
+
|
|
74
|
+
private _scaleDistanceStart: number = 0;
|
|
75
|
+
private _currentDistance: number = 1;
|
|
76
|
+
private _deltaDistance: number = 0;
|
|
77
|
+
|
|
78
|
+
constructor(session: XRSession) {
|
|
79
|
+
super();
|
|
80
|
+
|
|
81
|
+
this._session = session;
|
|
82
|
+
|
|
83
|
+
this._touches = [
|
|
84
|
+
{
|
|
85
|
+
start: new Vector2(),
|
|
86
|
+
current: new Vector2(),
|
|
87
|
+
delta: new Vector2(),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
start: new Vector2(),
|
|
91
|
+
current: new Vector2(),
|
|
92
|
+
delta: new Vector2(),
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
this._handleRotateStarted = false;
|
|
97
|
+
|
|
98
|
+
window.addEventListener('touchstart', (e: TouchEvent) =>
|
|
99
|
+
this.onTouchStart(e),
|
|
100
|
+
);
|
|
101
|
+
window.addEventListener('touchmove', (e: TouchEvent) =>
|
|
102
|
+
this.onTouchMove(e),
|
|
103
|
+
);
|
|
104
|
+
window.addEventListener('touchend', (e: TouchEvent) =>
|
|
105
|
+
this.onTouchEnd(e),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
this._session.addEventListener('selectstart', () =>
|
|
109
|
+
this.onSessionSelectStart(),
|
|
110
|
+
);
|
|
111
|
+
this._session.addEventListener('selectend', () =>
|
|
112
|
+
this.onSessionSelectEnd(),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public Dispose(): void {
|
|
117
|
+
window.removeEventListener('touchstart', (e: TouchEvent) =>
|
|
118
|
+
this.onTouchStart(e),
|
|
119
|
+
);
|
|
120
|
+
window.removeEventListener('touchmove', (e: TouchEvent) =>
|
|
121
|
+
this.onTouchMove(e),
|
|
122
|
+
);
|
|
123
|
+
window.removeEventListener('touchend', (e: TouchEvent) =>
|
|
124
|
+
this.onTouchEnd(e),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
this._session.removeEventListener('selectstart', () =>
|
|
128
|
+
this.onSessionSelectStart(),
|
|
129
|
+
);
|
|
130
|
+
this._session.removeEventListener('selectend', () =>
|
|
131
|
+
this.onSessionSelectEnd(),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private onTouchStart(event: TouchEvent): void {
|
|
136
|
+
this._touchCount = event.touches.length;
|
|
137
|
+
|
|
138
|
+
this._touches[0].start.set(
|
|
139
|
+
event.touches[0].clientX,
|
|
140
|
+
event.touches[0].clientY,
|
|
141
|
+
);
|
|
142
|
+
this._touches[0].current.set(
|
|
143
|
+
event.touches[0].clientX,
|
|
144
|
+
event.touches[0].clientY,
|
|
145
|
+
);
|
|
146
|
+
this._touches[0].delta.set(0, 0);
|
|
147
|
+
|
|
148
|
+
if (this._touchCount > 1) {
|
|
149
|
+
this._touches[1].start.set(
|
|
150
|
+
event.touches[1].clientX,
|
|
151
|
+
event.touches[1].clientY,
|
|
152
|
+
);
|
|
153
|
+
this._touches[1].current.set(
|
|
154
|
+
event.touches[1].clientX,
|
|
155
|
+
event.touches[1].clientY,
|
|
156
|
+
);
|
|
157
|
+
this._touches[1].delta.set(0, 0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (this._touchCount === 2) {
|
|
161
|
+
this.handleRotateStart();
|
|
162
|
+
this.handlePinchStart();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (this._handleRotateStarted) {
|
|
166
|
+
this.dispatch('ROTATE_START', {
|
|
167
|
+
current: 0,
|
|
168
|
+
});
|
|
169
|
+
this._handleRotateStarted = false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (this._handlePinchStarted) {
|
|
173
|
+
this.dispatch('PINCH_START', {
|
|
174
|
+
current: 0,
|
|
175
|
+
});
|
|
176
|
+
this._handlePinchStarted = false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private onTouchMove(event: TouchEvent): void {
|
|
181
|
+
this._touchCount = event.touches.length;
|
|
182
|
+
|
|
183
|
+
this._touches[0].start.set(
|
|
184
|
+
event.touches[0].clientX,
|
|
185
|
+
event.touches[0].clientY,
|
|
186
|
+
);
|
|
187
|
+
this._touches[0].current.set(
|
|
188
|
+
event.touches[0].clientX,
|
|
189
|
+
event.touches[0].clientY,
|
|
190
|
+
);
|
|
191
|
+
this._touches[0].delta.copy(
|
|
192
|
+
this._touches[0].current.clone().sub(this._touches[0].start),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
if (this._touchCount > 1) {
|
|
196
|
+
this._touches[1].start.set(
|
|
197
|
+
event.touches[1].clientX,
|
|
198
|
+
event.touches[1].clientY,
|
|
199
|
+
);
|
|
200
|
+
this._touches[1].current.set(
|
|
201
|
+
event.touches[1].clientX,
|
|
202
|
+
event.touches[1].clientY,
|
|
203
|
+
);
|
|
204
|
+
this._touches[1].delta.copy(
|
|
205
|
+
this._touches[1].current.clone().sub(this._touches[1].start),
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (this._touchCount === 2) {
|
|
210
|
+
this.handleRotateMoved();
|
|
211
|
+
this.handlePinchMoved();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (this._touchCount === 1) {
|
|
215
|
+
this.dispatch('TOUCH_MOVE', {
|
|
216
|
+
touches: [
|
|
217
|
+
{
|
|
218
|
+
current: this._touches[0].current.clone(),
|
|
219
|
+
delta: this._touches[0].delta.clone(),
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
current: this._touches[1].current.clone(),
|
|
223
|
+
delta: this._touches[1].delta.clone(),
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
touchCount: this._touchCount,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (this._touchCount === 2) {
|
|
231
|
+
if (this._handleRotateMoved) {
|
|
232
|
+
this.dispatch('ROTATE_MOVE', {
|
|
233
|
+
current: this._lastAngle,
|
|
234
|
+
delta: this._angleDelta,
|
|
235
|
+
});
|
|
236
|
+
this._handleRotateMoved = false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (this._handlePinchMoved) {
|
|
240
|
+
this.dispatch('PINCH_MOVE', {
|
|
241
|
+
current: this._currentDistance,
|
|
242
|
+
delta: this._deltaDistance,
|
|
243
|
+
});
|
|
244
|
+
this._handlePinchMoved = false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private onTouchEnd(event: TouchEvent): void {
|
|
250
|
+
this._touchCount = event.touches.length;
|
|
251
|
+
|
|
252
|
+
if (this._touchCount === 0) {
|
|
253
|
+
this._touches[0].start.set(0, 0);
|
|
254
|
+
this._touches[0].current.set(0, 0);
|
|
255
|
+
this._touches[0].delta.set(0, 0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (this._touchCount === 1) {
|
|
259
|
+
this.handleRotateEnded();
|
|
260
|
+
this.handlePinchEnded();
|
|
261
|
+
|
|
262
|
+
this._touches[1].start.set(0, 0);
|
|
263
|
+
this._touches[1].current.set(0, 0);
|
|
264
|
+
this._touches[1].delta.set(0, 0);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (this._handleRotateEnded) {
|
|
268
|
+
this.dispatch('ROTATE_END', {
|
|
269
|
+
current: this._lastAngle,
|
|
270
|
+
});
|
|
271
|
+
this._handleRotateEnded = false;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (this._handlePinchEnded) {
|
|
275
|
+
this.dispatch('PINCH_END', {
|
|
276
|
+
current: this._currentDistance,
|
|
277
|
+
});
|
|
278
|
+
this._handlePinchEnded = false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private onSessionSelectStart(): void {
|
|
283
|
+
this.dispatch('TOUCH_START', {
|
|
284
|
+
touches: [
|
|
285
|
+
{
|
|
286
|
+
current: this._touches[0].current.clone(),
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
current: this._touches[1].current.clone(),
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
touchCount: this._touchCount,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private onSessionSelectEnd(): void {
|
|
297
|
+
this.dispatch('TOUCH_END', {
|
|
298
|
+
touches: [
|
|
299
|
+
{
|
|
300
|
+
current: this._touches[0].current.clone(),
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
current: this._touches[1].current.clone(),
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
touchCount: this._touchCount,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// rotation handler
|
|
311
|
+
private handleRotateStart(): void {
|
|
312
|
+
this._handleRotateStarted = true;
|
|
313
|
+
this._startAngle = this._touches[1].start
|
|
314
|
+
.clone()
|
|
315
|
+
.sub(this._touches[0].current)
|
|
316
|
+
.angle();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
private handleRotateMoved(): void {
|
|
320
|
+
this._handleRotateMoved = true;
|
|
321
|
+
const currentAngle = this._touches[1].current
|
|
322
|
+
.clone()
|
|
323
|
+
.sub(this._touches[0].current)
|
|
324
|
+
.angle();
|
|
325
|
+
this._angleDelta = currentAngle - this._startAngle;
|
|
326
|
+
this._lastAngle = this._angleDelta * -1;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private handleRotateEnded(): void {
|
|
330
|
+
this._handleRotateEnded = true;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// pinch handler
|
|
334
|
+
private handlePinchStart(): void {
|
|
335
|
+
this._handlePinchStarted = true;
|
|
336
|
+
|
|
337
|
+
this._scaleDistanceStart = this._touches[1].start.distanceTo(
|
|
338
|
+
this._touches[0].current,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private handlePinchMoved(): void {
|
|
343
|
+
this._handlePinchMoved = true;
|
|
344
|
+
|
|
345
|
+
const beforeDistance = this._currentDistance;
|
|
346
|
+
const distance = this._touches[1].current.distanceTo(
|
|
347
|
+
this._touches[0].current,
|
|
348
|
+
);
|
|
349
|
+
this._currentDistance = distance / this._scaleDistanceStart;
|
|
350
|
+
this._deltaDistance = this._currentDistance - beforeDistance;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private handlePinchEnded(): void {
|
|
354
|
+
this._handlePinchEnded = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AxesHelper,
|
|
3
3
|
Color,
|
|
4
|
-
Material,
|
|
4
|
+
type Material,
|
|
5
5
|
Matrix4,
|
|
6
6
|
OrthographicCamera,
|
|
7
7
|
Vector4,
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
AxesColorGreenLetter,
|
|
17
17
|
AxesColorBlueLetter,
|
|
18
18
|
} from '../constant/AxisHelperColors.ts';
|
|
19
|
-
import { DIVERenderer } from '../renderer/Renderer.ts';
|
|
20
|
-
import { DIVEScene } from '../scene/Scene.ts';
|
|
21
|
-
import DIVEOrbitControls from '../controls/OrbitControls.ts';
|
|
19
|
+
import { type DIVERenderer } from '../renderer/Renderer.ts';
|
|
20
|
+
import { type DIVEScene } from '../scene/Scene.ts';
|
|
21
|
+
import type DIVEOrbitControls from '../controls/OrbitControls.ts';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Shows the scene axes in the bottom left corner of the screen.
|