@shopware-ag/dive 1.2.0 → 1.3.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/build/dive.cjs +288 -60
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +64 -6
- package/build/dive.d.ts +64 -6
- package/build/dive.js +289 -61
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/__test__/DIVE.test.ts +2 -0
- package/src/com/Communication.ts +6 -3
- package/src/com/__test__/Communication.test.ts +3 -6
- package/src/com/actions/object/getobjects.ts +2 -2
- package/src/dive.ts +7 -0
- package/src/gizmo/Gizmo.ts +130 -0
- package/src/gizmo/handles/AxisHandle.ts +124 -0
- package/src/gizmo/handles/RadialHandle.ts +119 -0
- package/src/gizmo/handles/ScaleHandle.ts +152 -0
- package/src/gizmo/plane/GizmoPlane.ts +85 -0
- package/src/gizmo/rotate/RotateGizmo.ts +95 -0
- package/src/gizmo/scale/ScaleGizmo.ts +97 -0
- package/src/gizmo/translate/TranslateGizmo.ts +88 -0
- package/src/interface/Draggable.ts +34 -0
- package/src/interface/Hoverable.ts +33 -0
- package/src/interface/Moveable.ts +0 -2
- package/src/interface/Selectable.ts +6 -0
- package/src/interface/__test__/Interfaces.test.ts +56 -0
- package/src/math/index.ts +3 -0
- package/src/math/signedAngleTo/__test__/signedAngleTo.test.ts +14 -0
- package/src/math/signedAngleTo/signedAngleTo.ts +13 -0
- package/src/scene/root/lightroot/LightRoot.ts +17 -3
- package/src/scene/root/lightroot/__test__/LightRoot.test.ts +12 -3
- package/src/scene/root/modelroot/ModelRoot.ts +17 -3
- package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +13 -14
- package/src/toolbox/BaseTool.ts +254 -4
- package/src/toolbox/Toolbox.ts +6 -0
- package/src/toolbox/__test__/BaseTool.test.ts +389 -0
- package/src/toolbox/__test__/Toolbox.test.ts +8 -0
- package/src/toolbox/select/SelectTool.ts +29 -65
- package/src/toolbox/select/__test__/SelectTool.test.ts +57 -25
- package/src/toolbox/transform/TransformTool.ts +48 -0
package/src/toolbox/BaseTool.ts
CHANGED
|
@@ -1,18 +1,268 @@
|
|
|
1
|
+
import { Intersection, Object3D, Raycaster, Vector2, Vector3 } from "three";
|
|
2
|
+
import { PRODUCT_LAYER_MASK, UI_LAYER_MASK } from "../constant/VisibilityLayerMask";
|
|
3
|
+
import DIVEScene from "../scene/Scene";
|
|
4
|
+
import DIVEOrbitControls from "../controls/OrbitControls";
|
|
5
|
+
import { DIVEDraggable, findDraggableInterface } from "../interface/Draggable";
|
|
6
|
+
import { DIVEHoverable, findHoverableInterface } from "../interface/Hoverable";
|
|
7
|
+
|
|
8
|
+
export type DraggableEvent = {
|
|
9
|
+
dragStart: Vector3;
|
|
10
|
+
dragCurrent: Vector3;
|
|
11
|
+
dragEnd: Vector3;
|
|
12
|
+
dragDelta: Vector3;
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
16
|
export default abstract class DIVEBaseTool {
|
|
3
|
-
|
|
17
|
+
readonly POINTER_DRAG_THRESHOLD: number = 0.001;
|
|
18
|
+
|
|
19
|
+
public name: string;
|
|
20
|
+
|
|
21
|
+
protected _canvas: HTMLElement;
|
|
22
|
+
protected _scene: DIVEScene;
|
|
23
|
+
protected _controller: DIVEOrbitControls;
|
|
24
|
+
|
|
25
|
+
// general pointer members
|
|
26
|
+
protected _pointer: Vector2;
|
|
27
|
+
|
|
28
|
+
protected get _pointerAnyDown(): boolean {
|
|
29
|
+
return this._pointerPrimaryDown
|
|
30
|
+
|| this._pointerMiddleDown
|
|
31
|
+
|| this._pointerSecondaryDown;
|
|
32
|
+
};
|
|
33
|
+
protected _pointerPrimaryDown: boolean;
|
|
34
|
+
protected _pointerMiddleDown: boolean;
|
|
35
|
+
protected _pointerSecondaryDown: boolean;
|
|
36
|
+
protected _lastPointerDown: Vector2;
|
|
37
|
+
protected _lastPointerUp: Vector2;
|
|
38
|
+
|
|
39
|
+
// raycast members
|
|
40
|
+
protected _raycaster: Raycaster;
|
|
41
|
+
protected _intersects: Intersection[];
|
|
4
42
|
|
|
5
|
-
|
|
43
|
+
// hovering members
|
|
44
|
+
protected _hovered: (Object3D & DIVEHoverable) | null;
|
|
45
|
+
|
|
46
|
+
// dragging members
|
|
47
|
+
protected _dragging: boolean;
|
|
48
|
+
protected _dragStart: Vector3;
|
|
49
|
+
protected _dragCurrent: Vector3;
|
|
50
|
+
protected _dragEnd: Vector3;
|
|
51
|
+
protected _dragDelta: Vector3;
|
|
52
|
+
protected _draggable: DIVEDraggable | null;
|
|
53
|
+
protected _dragRaycastOnObjects: Object3D[] | null;
|
|
54
|
+
|
|
55
|
+
protected constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
|
|
6
56
|
this.name = "BaseTool";
|
|
57
|
+
|
|
58
|
+
this._canvas = controller.domElement;
|
|
59
|
+
this._scene = scene;
|
|
60
|
+
this._controller = controller;
|
|
61
|
+
|
|
62
|
+
this._pointer = new Vector2();
|
|
63
|
+
|
|
64
|
+
this._pointerPrimaryDown = false;
|
|
65
|
+
this._pointerMiddleDown = false;
|
|
66
|
+
this._pointerSecondaryDown = false;
|
|
67
|
+
|
|
68
|
+
this._lastPointerDown = new Vector2();
|
|
69
|
+
this._lastPointerUp = new Vector2();
|
|
70
|
+
|
|
71
|
+
this._raycaster = new Raycaster();
|
|
72
|
+
this._raycaster.layers.mask = PRODUCT_LAYER_MASK | UI_LAYER_MASK;
|
|
73
|
+
this._intersects = [];
|
|
74
|
+
|
|
75
|
+
this._hovered = null;
|
|
76
|
+
|
|
77
|
+
this._dragging = false;
|
|
78
|
+
this._dragStart = new Vector3();
|
|
79
|
+
this._dragCurrent = new Vector3();
|
|
80
|
+
this._dragEnd = new Vector3();
|
|
81
|
+
this._dragDelta = new Vector3();
|
|
82
|
+
this._draggable = null;
|
|
83
|
+
this._dragRaycastOnObjects = null;
|
|
7
84
|
}
|
|
8
85
|
|
|
9
86
|
public Activate(): void { }
|
|
10
87
|
|
|
11
88
|
public Deactivate(): void { }
|
|
12
89
|
|
|
13
|
-
public onPointerDown(e: PointerEvent): void {
|
|
90
|
+
public onPointerDown(e: PointerEvent): void {
|
|
91
|
+
switch (e.button) {
|
|
92
|
+
case 0:
|
|
93
|
+
this._pointerPrimaryDown = true;
|
|
94
|
+
break;
|
|
95
|
+
case 1:
|
|
96
|
+
this._pointerMiddleDown = true;
|
|
97
|
+
break;
|
|
98
|
+
case 2:
|
|
99
|
+
this._pointerSecondaryDown = true;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this._lastPointerDown.copy(this._pointer);
|
|
104
|
+
|
|
105
|
+
this._draggable = findDraggableInterface(this._intersects[0]?.object) || null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public onDragStart(e: PointerEvent): void {
|
|
109
|
+
if (!this._draggable) return;
|
|
110
|
+
|
|
111
|
+
if (this._dragRaycastOnObjects !== null) {
|
|
112
|
+
this._intersects = this._raycaster.intersectObjects(this._dragRaycastOnObjects, true);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (this._intersects.length === 0) return;
|
|
116
|
+
|
|
117
|
+
this._dragStart.copy(this._intersects[0].point.clone());
|
|
118
|
+
this._dragCurrent.copy(this._intersects[0].point.clone());
|
|
119
|
+
this._dragEnd.copy(this._dragStart.clone());
|
|
120
|
+
this._dragDelta.set(0, 0, 0);
|
|
121
|
+
|
|
122
|
+
if (this._draggable && this._draggable.onDragStart) {
|
|
123
|
+
this._draggable.onDragStart({
|
|
124
|
+
dragStart: this._dragStart,
|
|
125
|
+
dragCurrent: this._dragCurrent,
|
|
126
|
+
dragEnd: this._dragEnd,
|
|
127
|
+
dragDelta: this._dragDelta,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
this._dragging = true;
|
|
131
|
+
this._controller.enabled = false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public onPointerMove(e: PointerEvent): void {
|
|
136
|
+
// update pointer
|
|
137
|
+
this._pointer.x = (e.offsetX / this._canvas.clientWidth) * 2 - 1;
|
|
138
|
+
this._pointer.y = -(e.offsetY / this._canvas.clientHeight) * 2 + 1;
|
|
139
|
+
|
|
140
|
+
// set raycaster
|
|
141
|
+
this._raycaster.setFromCamera(this._pointer, this._controller.object);
|
|
14
142
|
|
|
15
|
-
|
|
143
|
+
// refresh intersects
|
|
144
|
+
this._intersects = this.raycast(this._scene.children);
|
|
145
|
+
|
|
146
|
+
// handle hover
|
|
147
|
+
const hoverable = findHoverableInterface(this._intersects[0]?.object);
|
|
148
|
+
if (this._intersects[0] && hoverable) {
|
|
149
|
+
if (!this._hovered) {
|
|
150
|
+
if (hoverable.onPointerEnter) hoverable.onPointerEnter(this._intersects[0]);
|
|
151
|
+
this._hovered = hoverable;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this._hovered.uuid !== hoverable.uuid) {
|
|
156
|
+
if (this._hovered.onPointerLeave) this._hovered.onPointerLeave();
|
|
157
|
+
if (hoverable.onPointerEnter) hoverable.onPointerEnter(this._intersects[0]);
|
|
158
|
+
this._hovered = hoverable;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (hoverable.onPointerOver) hoverable.onPointerOver(this._intersects[0]);
|
|
163
|
+
this._hovered = hoverable;
|
|
164
|
+
|
|
165
|
+
} else {
|
|
166
|
+
if (this._hovered) {
|
|
167
|
+
if (this._hovered.onPointerLeave) this._hovered.onPointerLeave();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this._hovered = null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// handle drag
|
|
174
|
+
if (this._pointerAnyDown) {
|
|
175
|
+
if (!this._dragging) {
|
|
176
|
+
this.onDragStart(e);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.onDrag(e);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public onDrag(e: PointerEvent): void {
|
|
184
|
+
if (this._dragRaycastOnObjects !== null) {
|
|
185
|
+
this._intersects = this._raycaster.intersectObjects(this._dragRaycastOnObjects, true);
|
|
186
|
+
}
|
|
187
|
+
const intersect = this._intersects[0];
|
|
188
|
+
if (!intersect) return;
|
|
189
|
+
|
|
190
|
+
this._dragCurrent.copy(intersect.point.clone());
|
|
191
|
+
this._dragEnd.copy(intersect.point.clone());
|
|
192
|
+
this._dragDelta.subVectors(this._dragCurrent.clone(), this._dragStart.clone());
|
|
193
|
+
|
|
194
|
+
if (this._draggable && this._draggable.onDrag) {
|
|
195
|
+
this._draggable.onDrag({
|
|
196
|
+
dragStart: this._dragStart,
|
|
197
|
+
dragCurrent: this._dragCurrent,
|
|
198
|
+
dragEnd: this._dragEnd,
|
|
199
|
+
dragDelta: this._dragDelta,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public onPointerUp(e: PointerEvent): void {
|
|
205
|
+
if (this.pointerWasDragged() || this._dragging) {
|
|
206
|
+
if (this._draggable) {
|
|
207
|
+
this.onDragEnd(e);
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
this.onClick(e);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
switch (e.button) {
|
|
214
|
+
case 0:
|
|
215
|
+
this._pointerPrimaryDown = false;
|
|
216
|
+
break;
|
|
217
|
+
case 1:
|
|
218
|
+
this._pointerMiddleDown = false;
|
|
219
|
+
break;
|
|
220
|
+
case 2:
|
|
221
|
+
this._pointerSecondaryDown = false;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this._lastPointerUp.copy(this._pointer);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public onClick(e: PointerEvent): void { }
|
|
229
|
+
|
|
230
|
+
public onDragEnd(e: PointerEvent): void {
|
|
231
|
+
const intersect = this._intersects[0];
|
|
232
|
+
if (intersect) {
|
|
233
|
+
this._dragEnd.copy(intersect.point.clone());
|
|
234
|
+
this._dragCurrent.copy(intersect.point.clone());
|
|
235
|
+
this._dragDelta.subVectors(this._dragCurrent.clone(), this._dragStart.clone());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (this._draggable && this._draggable.onDragEnd) {
|
|
239
|
+
this._draggable.onDragEnd({
|
|
240
|
+
dragStart: this._dragStart,
|
|
241
|
+
dragCurrent: this._dragCurrent,
|
|
242
|
+
dragEnd: this._dragEnd,
|
|
243
|
+
dragDelta: this._dragDelta,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
this._draggable = null;
|
|
248
|
+
this._dragging = false;
|
|
249
|
+
|
|
250
|
+
this._dragStart.set(0, 0, 0);
|
|
251
|
+
this._dragCurrent.set(0, 0, 0);
|
|
252
|
+
this._dragEnd.set(0, 0, 0);
|
|
253
|
+
this._dragDelta.set(0, 0, 0);
|
|
254
|
+
|
|
255
|
+
this._controller.enabled = true;
|
|
256
|
+
}
|
|
16
257
|
|
|
17
258
|
public onWheel(e: WheelEvent): void { }
|
|
259
|
+
|
|
260
|
+
protected raycast(objects?: Object3D[]): Intersection[] {
|
|
261
|
+
if (objects !== undefined) return this._raycaster.intersectObjects(objects, true);
|
|
262
|
+
return this._raycaster.intersectObjects(this._scene.children, true);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private pointerWasDragged(): boolean {
|
|
266
|
+
return this._lastPointerDown.distanceTo(this._pointer) > this.POINTER_DRAG_THRESHOLD;
|
|
267
|
+
}
|
|
18
268
|
}
|
package/src/toolbox/Toolbox.ts
CHANGED
|
@@ -21,11 +21,13 @@ export default class DIVEToolbox {
|
|
|
21
21
|
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
|
|
22
22
|
this.selectTool = new DIVESelectTool(scene, controller);
|
|
23
23
|
|
|
24
|
+
controller.domElement.addEventListener('pointermove', this.onPointerMove.bind(this));
|
|
24
25
|
controller.domElement.addEventListener('pointerdown', this.onPointerDown.bind(this));
|
|
25
26
|
controller.domElement.addEventListener('pointerup', this.onPointerUp.bind(this));
|
|
26
27
|
controller.domElement.addEventListener('wheel', this.onWheel.bind(this));
|
|
27
28
|
|
|
28
29
|
this.removeListenersCallback = () => {
|
|
30
|
+
controller.domElement.removeEventListener('pointermove', this.onPointerMove.bind(this));
|
|
29
31
|
controller.domElement.removeEventListener('pointerdown', this.onPointerDown.bind(this));
|
|
30
32
|
controller.domElement.removeEventListener('pointerup', this.onPointerUp.bind(this));
|
|
31
33
|
controller.domElement.removeEventListener('wheel', this.onWheel.bind(this));
|
|
@@ -62,6 +64,10 @@ export default class DIVEToolbox {
|
|
|
62
64
|
this.selectTool.SetGizmoMode(mode);
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
public onPointerMove(e: PointerEvent): void {
|
|
68
|
+
this.activeTool.onPointerMove(e);
|
|
69
|
+
}
|
|
70
|
+
|
|
65
71
|
public onPointerDown(e: PointerEvent): void {
|
|
66
72
|
this.activeTool.onPointerDown(e);
|
|
67
73
|
}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
|
|
2
|
+
import { type Object3D, type Vector3 } from 'three';
|
|
3
|
+
import DIVEOrbitControls from '../../controls/OrbitControls';
|
|
4
|
+
import DIVEScene from '../../scene/Scene';
|
|
5
|
+
import DIVEBaseTool from '../BaseTool';
|
|
6
|
+
import DIVEToolbox from '../Toolbox';
|
|
7
|
+
import { type DIVEHoverable } from '../../interface/Hoverable';
|
|
8
|
+
import { DIVEDraggable } from '../../interface/Draggable';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @jest-environment jsdom
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const mock_Canvas = {
|
|
16
|
+
width: 0,
|
|
17
|
+
height: 0,
|
|
18
|
+
getContext: jest.fn(),
|
|
19
|
+
clientWidth: 1000,
|
|
20
|
+
clientHeight: 1000,
|
|
21
|
+
offsetLeft: 0,
|
|
22
|
+
offsetTop: 0,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const mockController = {
|
|
26
|
+
domElement: mock_Canvas,
|
|
27
|
+
object: {
|
|
28
|
+
isPerspectiveCamera: true,
|
|
29
|
+
type: 'cameraP'
|
|
30
|
+
}
|
|
31
|
+
} as unknown as DIVEOrbitControls;
|
|
32
|
+
|
|
33
|
+
const mockScene = {
|
|
34
|
+
children: [],
|
|
35
|
+
} as unknown as DIVEScene;
|
|
36
|
+
|
|
37
|
+
const abstractWrapper = class Wrapper extends DIVEBaseTool {
|
|
38
|
+
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
|
|
39
|
+
super(scene, controller);
|
|
40
|
+
this.name = "DIVEBaseTool";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('dive/toolbox/DIVEBaseTool', () => {
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
jest.clearAllMocks();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should instantiate', () => {
|
|
50
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
51
|
+
expect(toolBox).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should raycast', () => {
|
|
55
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
56
|
+
expect(() => toolBox['raycast']()).not.toThrow();
|
|
57
|
+
expect(() => toolBox['raycast']([])).not.toThrow();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return correct pointerAnyDown', () => {
|
|
61
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
62
|
+
expect(toolBox).toBeDefined();
|
|
63
|
+
expect(toolBox['_pointerAnyDown']).toBeDefined();
|
|
64
|
+
expect(toolBox['_pointerAnyDown']).toBe(false);
|
|
65
|
+
|
|
66
|
+
toolBox['_pointerPrimaryDown'] = true;
|
|
67
|
+
expect(toolBox['_pointerAnyDown']).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should execute onPointerDown correctly', () => {
|
|
71
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
72
|
+
expect(() => toolBox.onPointerDown({ button: 0 } as PointerEvent)).not.toThrow();
|
|
73
|
+
expect(() => toolBox.onPointerDown({ button: 1 } as PointerEvent)).not.toThrow();
|
|
74
|
+
expect(() => toolBox.onPointerDown({ button: 2 } as PointerEvent)).not.toThrow();
|
|
75
|
+
|
|
76
|
+
toolBox['_intersects'] = [
|
|
77
|
+
{
|
|
78
|
+
distance: 1,
|
|
79
|
+
point: {
|
|
80
|
+
clone() {
|
|
81
|
+
return {
|
|
82
|
+
x: 1,
|
|
83
|
+
y: 1,
|
|
84
|
+
z: 1
|
|
85
|
+
} as unknown as Vector3;
|
|
86
|
+
},
|
|
87
|
+
x: 1,
|
|
88
|
+
y: 1,
|
|
89
|
+
z: 1
|
|
90
|
+
} as unknown as Vector3,
|
|
91
|
+
object: {
|
|
92
|
+
uuid: 'uuid2',
|
|
93
|
+
isHoverable: true,
|
|
94
|
+
onPointerEnter() {
|
|
95
|
+
return;
|
|
96
|
+
},
|
|
97
|
+
} as unknown as Object3D & DIVEHoverable
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
expect(() => toolBox.onPointerDown({ button: 0 } as PointerEvent)).not.toThrow();
|
|
102
|
+
expect(() => toolBox.onPointerDown({ button: 1 } as PointerEvent)).not.toThrow();
|
|
103
|
+
expect(() => toolBox.onPointerDown({ button: 2 } as PointerEvent)).not.toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should execute onPointerMove correctly', () => {
|
|
107
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
108
|
+
jest.spyOn(toolBox['_raycaster'], 'setFromCamera').mockImplementation();
|
|
109
|
+
|
|
110
|
+
// test with no hit with hovered object before
|
|
111
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce([]);
|
|
112
|
+
|
|
113
|
+
toolBox['_hovered'] = {
|
|
114
|
+
uuid: 'uuid',
|
|
115
|
+
onPointerLeave() {
|
|
116
|
+
return;
|
|
117
|
+
},
|
|
118
|
+
} as Object3D & DIVEHoverable;
|
|
119
|
+
|
|
120
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
121
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
122
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
123
|
+
|
|
124
|
+
// test with no hovered object
|
|
125
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce(
|
|
126
|
+
[
|
|
127
|
+
{
|
|
128
|
+
distance: 1,
|
|
129
|
+
point: {
|
|
130
|
+
x: 1,
|
|
131
|
+
y: 1,
|
|
132
|
+
z: 1
|
|
133
|
+
} as unknown as Vector3,
|
|
134
|
+
object: {
|
|
135
|
+
uuid: 'uuid',
|
|
136
|
+
isHoverable: true,
|
|
137
|
+
} as Object3D & DIVEHoverable
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
toolBox['_hovered'] = null;
|
|
143
|
+
|
|
144
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
145
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
146
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
147
|
+
|
|
148
|
+
// test with no hovered object with onPointerEnter
|
|
149
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce(
|
|
150
|
+
[
|
|
151
|
+
{
|
|
152
|
+
distance: 1,
|
|
153
|
+
point: {
|
|
154
|
+
x: 1,
|
|
155
|
+
y: 1,
|
|
156
|
+
z: 1
|
|
157
|
+
} as unknown as Vector3,
|
|
158
|
+
object: {
|
|
159
|
+
uuid: 'uuid',
|
|
160
|
+
isHoverable: true,
|
|
161
|
+
onPointerEnter() {
|
|
162
|
+
return;
|
|
163
|
+
},
|
|
164
|
+
} as unknown as Object3D & DIVEHoverable
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
170
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
171
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
172
|
+
|
|
173
|
+
// test with same hovered object
|
|
174
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce(
|
|
175
|
+
[
|
|
176
|
+
{
|
|
177
|
+
distance: 1,
|
|
178
|
+
point: {
|
|
179
|
+
x: 1,
|
|
180
|
+
y: 1,
|
|
181
|
+
z: 1
|
|
182
|
+
} as unknown as Vector3,
|
|
183
|
+
object: {
|
|
184
|
+
uuid: 'uuid',
|
|
185
|
+
isHoverable: true,
|
|
186
|
+
onPointerOver() {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
} as unknown as Object3D & DIVEHoverable
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
toolBox['_hovered'] = {
|
|
195
|
+
uuid: 'uuid',
|
|
196
|
+
onPointerLeave() {
|
|
197
|
+
return;
|
|
198
|
+
},
|
|
199
|
+
} as Object3D & DIVEHoverable;
|
|
200
|
+
|
|
201
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
202
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
203
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
204
|
+
|
|
205
|
+
// test with different hovered object
|
|
206
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce(
|
|
207
|
+
[
|
|
208
|
+
{
|
|
209
|
+
distance: 1,
|
|
210
|
+
point: {
|
|
211
|
+
x: 1,
|
|
212
|
+
y: 1,
|
|
213
|
+
z: 1
|
|
214
|
+
} as unknown as Vector3,
|
|
215
|
+
object: {
|
|
216
|
+
uuid: 'uuid2',
|
|
217
|
+
isHoverable: true,
|
|
218
|
+
onPointerEnter() {
|
|
219
|
+
return;
|
|
220
|
+
},
|
|
221
|
+
} as unknown as Object3D & DIVEHoverable
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
toolBox['_hovered'] = {
|
|
227
|
+
uuid: 'uuid',
|
|
228
|
+
onPointerLeave() {
|
|
229
|
+
return;
|
|
230
|
+
},
|
|
231
|
+
} as Object3D & DIVEHoverable;
|
|
232
|
+
|
|
233
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
234
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
235
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
236
|
+
|
|
237
|
+
// test with pointer down
|
|
238
|
+
toolBox['_pointerPrimaryDown'] = true;
|
|
239
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
240
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
241
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
242
|
+
|
|
243
|
+
// test with pointer down while already dragging
|
|
244
|
+
toolBox['_pointerPrimaryDown'] = true;
|
|
245
|
+
toolBox['_dragging'] = true;
|
|
246
|
+
expect(() => toolBox.onPointerMove({ button: 0, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
247
|
+
expect(() => toolBox.onPointerMove({ button: 1, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
248
|
+
expect(() => toolBox.onPointerMove({ button: 2, offsetX: 100, offsetY: 100 } as PointerEvent)).not.toThrow();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should execute onPointerUp correctly', () => {
|
|
252
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
253
|
+
expect(() => toolBox.onPointerUp({ button: 0 } as PointerEvent)).not.toThrow();
|
|
254
|
+
expect(() => toolBox.onPointerUp({ button: 1 } as PointerEvent)).not.toThrow();
|
|
255
|
+
expect(() => toolBox.onPointerUp({ button: 2 } as PointerEvent)).not.toThrow();
|
|
256
|
+
|
|
257
|
+
toolBox['pointerWasDragged'] = () => { return true; };
|
|
258
|
+
toolBox['_dragging'] = true;
|
|
259
|
+
toolBox['_intersects'] = [
|
|
260
|
+
{
|
|
261
|
+
distance: 1,
|
|
262
|
+
point: {
|
|
263
|
+
clone() {
|
|
264
|
+
return {
|
|
265
|
+
x: 1,
|
|
266
|
+
y: 1,
|
|
267
|
+
z: 1
|
|
268
|
+
} as unknown as Vector3;
|
|
269
|
+
},
|
|
270
|
+
x: 1,
|
|
271
|
+
y: 1,
|
|
272
|
+
z: 1
|
|
273
|
+
} as unknown as Vector3,
|
|
274
|
+
object: {
|
|
275
|
+
uuid: 'uuid2',
|
|
276
|
+
isHoverable: true,
|
|
277
|
+
onPointerEnter() {
|
|
278
|
+
return;
|
|
279
|
+
},
|
|
280
|
+
} as unknown as Object3D & DIVEHoverable
|
|
281
|
+
}
|
|
282
|
+
];
|
|
283
|
+
toolBox['_draggable'] = {
|
|
284
|
+
onDragEnd() {
|
|
285
|
+
return;
|
|
286
|
+
},
|
|
287
|
+
} as unknown as Object3D & DIVEDraggable;
|
|
288
|
+
expect(() => toolBox.onPointerUp({ button: 0 } as PointerEvent)).not.toThrow();
|
|
289
|
+
expect(() => toolBox.onPointerUp({ button: 1 } as PointerEvent)).not.toThrow();
|
|
290
|
+
expect(() => toolBox.onPointerUp({ button: 2 } as PointerEvent)).not.toThrow();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('should execute onDragStart correctly', () => {
|
|
294
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
295
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
296
|
+
|
|
297
|
+
toolBox['_draggable'] = {
|
|
298
|
+
onDragStart() {
|
|
299
|
+
return;
|
|
300
|
+
},
|
|
301
|
+
} as unknown as Object3D & DIVEDraggable;
|
|
302
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
303
|
+
|
|
304
|
+
toolBox['_dragRaycastOnObjects'] = [];
|
|
305
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
306
|
+
|
|
307
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce([]);
|
|
308
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
309
|
+
|
|
310
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce([
|
|
311
|
+
{
|
|
312
|
+
distance: 1,
|
|
313
|
+
point: {
|
|
314
|
+
clone() {
|
|
315
|
+
return {
|
|
316
|
+
x: 1,
|
|
317
|
+
y: 1,
|
|
318
|
+
z: 1
|
|
319
|
+
} as unknown as Vector3;
|
|
320
|
+
},
|
|
321
|
+
x: 1,
|
|
322
|
+
y: 1,
|
|
323
|
+
z: 1
|
|
324
|
+
} as unknown as Vector3,
|
|
325
|
+
object: {
|
|
326
|
+
uuid: 'uuid2',
|
|
327
|
+
isHoverable: true,
|
|
328
|
+
onPointerEnter() {
|
|
329
|
+
return;
|
|
330
|
+
},
|
|
331
|
+
} as unknown as Object3D & DIVEHoverable
|
|
332
|
+
}
|
|
333
|
+
]);
|
|
334
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
335
|
+
|
|
336
|
+
toolBox['_draggable'] = {
|
|
337
|
+
onDragStart() {
|
|
338
|
+
return;
|
|
339
|
+
},
|
|
340
|
+
} as unknown as Object3D & DIVEDraggable;
|
|
341
|
+
expect(() => toolBox.onDragStart({} as PointerEvent)).not.toThrow();
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should execute onDrag correctly', () => {
|
|
345
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
346
|
+
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
|
|
347
|
+
|
|
348
|
+
toolBox['_dragRaycastOnObjects'] = [];
|
|
349
|
+
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
|
|
350
|
+
|
|
351
|
+
toolBox['_draggable'] = {
|
|
352
|
+
onDrag() {
|
|
353
|
+
return;
|
|
354
|
+
},
|
|
355
|
+
} as unknown as Object3D & DIVEDraggable;
|
|
356
|
+
jest.spyOn(toolBox['_raycaster'], 'intersectObjects').mockReturnValueOnce(
|
|
357
|
+
[
|
|
358
|
+
{
|
|
359
|
+
distance: 1,
|
|
360
|
+
point: {
|
|
361
|
+
clone() {
|
|
362
|
+
return {
|
|
363
|
+
x: 1,
|
|
364
|
+
y: 1,
|
|
365
|
+
z: 1
|
|
366
|
+
} as unknown as Vector3;
|
|
367
|
+
},
|
|
368
|
+
x: 1,
|
|
369
|
+
y: 1,
|
|
370
|
+
z: 1
|
|
371
|
+
} as unknown as Vector3,
|
|
372
|
+
object: {
|
|
373
|
+
uuid: 'uuid2',
|
|
374
|
+
isHoverable: true,
|
|
375
|
+
onPointerEnter() {
|
|
376
|
+
return;
|
|
377
|
+
},
|
|
378
|
+
} as unknown as Object3D & DIVEHoverable
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
);
|
|
382
|
+
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('should execute onDragEnd correctly', () => {
|
|
386
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
387
|
+
expect(() => toolBox.onDragEnd({} as PointerEvent)).not.toThrow();
|
|
388
|
+
});
|
|
389
|
+
});
|