@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.
Files changed (39) hide show
  1. package/build/dive.cjs +288 -60
  2. package/build/dive.cjs.map +1 -1
  3. package/build/dive.d.cts +64 -6
  4. package/build/dive.d.ts +64 -6
  5. package/build/dive.js +289 -61
  6. package/build/dive.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__test__/DIVE.test.ts +2 -0
  9. package/src/com/Communication.ts +6 -3
  10. package/src/com/__test__/Communication.test.ts +3 -6
  11. package/src/com/actions/object/getobjects.ts +2 -2
  12. package/src/dive.ts +7 -0
  13. package/src/gizmo/Gizmo.ts +130 -0
  14. package/src/gizmo/handles/AxisHandle.ts +124 -0
  15. package/src/gizmo/handles/RadialHandle.ts +119 -0
  16. package/src/gizmo/handles/ScaleHandle.ts +152 -0
  17. package/src/gizmo/plane/GizmoPlane.ts +85 -0
  18. package/src/gizmo/rotate/RotateGizmo.ts +95 -0
  19. package/src/gizmo/scale/ScaleGizmo.ts +97 -0
  20. package/src/gizmo/translate/TranslateGizmo.ts +88 -0
  21. package/src/interface/Draggable.ts +34 -0
  22. package/src/interface/Hoverable.ts +33 -0
  23. package/src/interface/Moveable.ts +0 -2
  24. package/src/interface/Selectable.ts +6 -0
  25. package/src/interface/__test__/Interfaces.test.ts +56 -0
  26. package/src/math/index.ts +3 -0
  27. package/src/math/signedAngleTo/__test__/signedAngleTo.test.ts +14 -0
  28. package/src/math/signedAngleTo/signedAngleTo.ts +13 -0
  29. package/src/scene/root/lightroot/LightRoot.ts +17 -3
  30. package/src/scene/root/lightroot/__test__/LightRoot.test.ts +12 -3
  31. package/src/scene/root/modelroot/ModelRoot.ts +17 -3
  32. package/src/scene/root/modelroot/__test__/ModelRoot.test.ts +13 -14
  33. package/src/toolbox/BaseTool.ts +254 -4
  34. package/src/toolbox/Toolbox.ts +6 -0
  35. package/src/toolbox/__test__/BaseTool.test.ts +389 -0
  36. package/src/toolbox/__test__/Toolbox.test.ts +8 -0
  37. package/src/toolbox/select/SelectTool.ts +29 -65
  38. package/src/toolbox/select/__test__/SelectTool.test.ts +57 -25
  39. package/src/toolbox/transform/TransformTool.ts +48 -0
@@ -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
- protected name: string;
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
- protected constructor() {
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
- public onPointerUp(e: PointerEvent): void { }
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
  }
@@ -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
+ });