@shopware-ag/dive 1.5.0 → 1.6.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/README.md +38 -25
- package/build/dive.cjs +717 -500
- package/build/dive.cjs.map +1 -1
- package/build/dive.d.cts +174 -113
- package/build/dive.d.ts +174 -113
- package/build/dive.js +716 -486
- package/build/dive.js.map +1 -1
- package/package.json +1 -1
- package/src/__test__/DIVE.test.ts +66 -22
- package/src/animation/AnimationSystem.ts +16 -0
- package/src/animation/__test__/AnimationSystem.test.ts +23 -2
- package/src/axiscamera/AxisCamera.ts +40 -2
- package/src/axiscamera/__test__/AxisCamera.test.ts +178 -5
- package/src/com/Communication.ts +50 -16
- package/src/com/__test__/Communication.test.ts +73 -24
- package/src/com/actions/camera/computeencompassingview.ts +9 -0
- package/src/com/actions/index.ts +2 -0
- package/src/com/actions/scene/updatescene.ts +1 -0
- package/src/controls/OrbitControls.ts +14 -2
- package/src/controls/__test__/OrbitControls.test.ts +31 -4
- package/src/dive.ts +93 -33
- package/src/grid/Grid.ts +4 -0
- package/src/grid/__test__/Grid.test.ts +7 -0
- package/src/interface/Selectable.ts +17 -0
- package/src/interface/__test__/Interfaces.test.ts +18 -0
- package/src/mediacreator/MediaCreator.ts +2 -2
- package/src/mediacreator/__test__/MediaCreator.test.ts +12 -10
- package/src/renderer/Renderer.ts +7 -1
- package/src/renderer/__test__/Renderer.test.ts +14 -5
- package/src/scene/Scene.ts +8 -2
- package/src/scene/__test__/Scene.test.ts +6 -0
- package/src/scene/root/Root.ts +11 -1
- package/src/scene/root/__test__/Root.test.ts +68 -2
- package/src/toolbox/BaseTool.ts +1 -1
- package/src/toolbox/Toolbox.ts +53 -37
- package/src/toolbox/__test__/BaseTool.test.ts +43 -7
- package/src/toolbox/__test__/Toolbox.test.ts +39 -44
- package/src/toolbox/select/SelectTool.ts +17 -28
- package/src/toolbox/select/__test__/SelectTool.test.ts +21 -12
- package/src/toolbox/transform/TransformTool.ts +7 -1
- package/src/toolbox/transform/__test__/TransformTool.test.ts +22 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
|
|
2
|
-
import DIVEScene from '../../scene/Scene';
|
|
3
|
-
import DIVERenderer,
|
|
1
|
+
import type DIVEPerspectiveCamera from '../../camera/PerspectiveCamera';
|
|
2
|
+
import type DIVEScene from '../../scene/Scene';
|
|
3
|
+
import { DIVERenderer, DIVERendererDefaultSettings } from '../Renderer';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @jest-environment jsdom
|
|
@@ -20,6 +20,7 @@ jest.mock('three', () => {
|
|
|
20
20
|
position: 'absolute',
|
|
21
21
|
},
|
|
22
22
|
};
|
|
23
|
+
this.dispose = jest.fn();
|
|
23
24
|
this.debug = {
|
|
24
25
|
checkShaderErrors: true,
|
|
25
26
|
};
|
|
@@ -43,12 +44,20 @@ let renderer: DIVERenderer;
|
|
|
43
44
|
describe('dive/renderer/DIVERenderer', () => {
|
|
44
45
|
beforeEach(() => {
|
|
45
46
|
jest.clearAllMocks();
|
|
46
|
-
renderer = new DIVERenderer(
|
|
47
|
+
renderer = new DIVERenderer();
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
it('should instantiate', () => {
|
|
50
51
|
expect(renderer).toBeDefined();
|
|
51
|
-
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should instantiate with settings parameter', () => {
|
|
55
|
+
renderer = new DIVERenderer(DIVERendererDefaultSettings);
|
|
56
|
+
expect(renderer).toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should dispose', () => {
|
|
60
|
+
renderer.Dispose();
|
|
52
61
|
});
|
|
53
62
|
|
|
54
63
|
it('should start render', () => {
|
package/src/scene/Scene.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Color, ColorRepresentation, Object3D
|
|
2
|
-
import { COMModel, COMEntity } from '../com/types';
|
|
1
|
+
import { Color, Scene, type Box3, type ColorRepresentation, type Object3D } from 'three';
|
|
2
|
+
import { type COMModel, type COMEntity } from '../com/types';
|
|
3
3
|
import DIVERoot from './root/Root';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -19,6 +19,8 @@ export default class DIVEScene extends Scene {
|
|
|
19
19
|
constructor() {
|
|
20
20
|
super();
|
|
21
21
|
|
|
22
|
+
this.background = new Color(0xffffff);
|
|
23
|
+
|
|
22
24
|
this.root = new DIVERoot();
|
|
23
25
|
this.add(this.root);
|
|
24
26
|
}
|
|
@@ -27,6 +29,10 @@ export default class DIVEScene extends Scene {
|
|
|
27
29
|
this.background = new Color(color);
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
public ComputeSceneBB(): Box3 {
|
|
33
|
+
return this.Root.ComputeSceneBB();
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
public GetSceneObject(object: Partial<COMEntity>): Object3D | undefined {
|
|
31
37
|
return this.Root.GetSceneObject(object);
|
|
32
38
|
}
|
|
@@ -17,6 +17,7 @@ jest.mock('../root/Root', () => {
|
|
|
17
17
|
this.PlaceOnFloor = mock_PlaceOnFloor;
|
|
18
18
|
this.GetSceneObject = mock_GetSceneObject;
|
|
19
19
|
this.removeFromParent = jest.fn();
|
|
20
|
+
this.ComputeSceneBB = jest.fn();
|
|
20
21
|
return this;
|
|
21
22
|
});
|
|
22
23
|
});
|
|
@@ -38,6 +39,11 @@ describe('dive/scene/DIVEScene', () => {
|
|
|
38
39
|
expect((scene.background as Color).getHex()).toBe(0x123456);
|
|
39
40
|
});
|
|
40
41
|
|
|
42
|
+
it('should ComputeSceneBB', () => {
|
|
43
|
+
const scene = new DIVEScene();
|
|
44
|
+
expect(() => scene.ComputeSceneBB()).not.toThrow();
|
|
45
|
+
});
|
|
46
|
+
|
|
41
47
|
it('should add object', () => {
|
|
42
48
|
const scene = new DIVEScene();
|
|
43
49
|
scene.AddSceneObject({} as COMEntity);
|
package/src/scene/root/Root.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Object3D } from "three";
|
|
1
|
+
import { Box3, Object3D } from "three";
|
|
2
2
|
import DIVELightRoot from "./lightroot/LightRoot.ts";
|
|
3
3
|
import DIVEModelRoot from "./modelroot/ModelRoot.ts";
|
|
4
4
|
import { COMLight, COMModel, COMEntity } from "../../com/types.ts";
|
|
@@ -39,6 +39,16 @@ export default class DIVERoot extends Object3D {
|
|
|
39
39
|
this.add(this.grid);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
public ComputeSceneBB(): Box3 {
|
|
43
|
+
const bb = new Box3();
|
|
44
|
+
this.modelRoot.traverse((object: Object3D) => {
|
|
45
|
+
if ('isObject3D' in object) {
|
|
46
|
+
bb.expandByObject(object);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return bb;
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
public GetSceneObject(object: Partial<COMEntity>): Object3D | undefined {
|
|
43
53
|
switch (object.entityType) {
|
|
44
54
|
case "pov": {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { COMLight, COMModel, COMPov } from '../../../com';
|
|
2
1
|
import DIVERoot from '../Root';
|
|
2
|
+
import { type Vector3, type Object3D } from 'three';
|
|
3
|
+
import { type COMLight, type COMModel, type COMPov } from '../../../com';
|
|
3
4
|
|
|
4
5
|
const mock_UpdateLight = jest.fn();
|
|
5
6
|
const mock_UpdateModel = jest.fn();
|
|
@@ -9,6 +10,62 @@ const mock_DeleteLight = jest.fn();
|
|
|
9
10
|
const mock_DeleteModel = jest.fn();
|
|
10
11
|
const mock_PlaceOnFloor = jest.fn();
|
|
11
12
|
|
|
13
|
+
jest.mock('three', () => {
|
|
14
|
+
return {
|
|
15
|
+
Box3: jest.fn(() => {
|
|
16
|
+
return {
|
|
17
|
+
expandByObject: jest.fn(),
|
|
18
|
+
setFromObject: jest.fn(),
|
|
19
|
+
applyMatrix4: jest.fn(),
|
|
20
|
+
union: jest.fn(),
|
|
21
|
+
isEmpty: jest.fn(),
|
|
22
|
+
getCenter: jest.fn(),
|
|
23
|
+
getSize: jest.fn(),
|
|
24
|
+
getBoundingSphere: jest.fn(),
|
|
25
|
+
};
|
|
26
|
+
}),
|
|
27
|
+
Object3D: jest.fn(function () {
|
|
28
|
+
this.clear = jest.fn();
|
|
29
|
+
this.color = {};
|
|
30
|
+
this.intensity = 0;
|
|
31
|
+
this.layers = {
|
|
32
|
+
mask: 0,
|
|
33
|
+
};
|
|
34
|
+
this.shadow = {
|
|
35
|
+
radius: 0,
|
|
36
|
+
mapSize: { width: 0, height: 0 },
|
|
37
|
+
bias: 0,
|
|
38
|
+
camera: {
|
|
39
|
+
near: 0,
|
|
40
|
+
far: 0,
|
|
41
|
+
fov: 0,
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
this.add = jest.fn();
|
|
45
|
+
this.userData = {};
|
|
46
|
+
this.rotation = {
|
|
47
|
+
x: 0,
|
|
48
|
+
y: 0,
|
|
49
|
+
z: 0,
|
|
50
|
+
setFromVector3: jest.fn(),
|
|
51
|
+
};
|
|
52
|
+
this.scale = {
|
|
53
|
+
x: 1,
|
|
54
|
+
y: 1,
|
|
55
|
+
z: 1,
|
|
56
|
+
set: jest.fn(),
|
|
57
|
+
};
|
|
58
|
+
this.localToWorld = (vec3: Vector3) => {
|
|
59
|
+
return vec3;
|
|
60
|
+
};
|
|
61
|
+
this.traverse = jest.fn((callback) => {
|
|
62
|
+
callback(this.children[0])
|
|
63
|
+
});
|
|
64
|
+
return this;
|
|
65
|
+
}),
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
12
69
|
jest.mock('../../../primitive/floor/Floor', () => {
|
|
13
70
|
return jest.fn(function () {
|
|
14
71
|
this.isObject3D = true;
|
|
@@ -52,6 +109,9 @@ jest.mock('../modelroot/ModelRoot', () => {
|
|
|
52
109
|
this.PlaceOnFloor = mock_PlaceOnFloor;
|
|
53
110
|
this.GetModel = mock_GetModel;
|
|
54
111
|
this.removeFromParent = jest.fn();
|
|
112
|
+
this.traverse = jest.fn((callback: (object: Object3D) => void) => {
|
|
113
|
+
callback(this);
|
|
114
|
+
});
|
|
55
115
|
return this;
|
|
56
116
|
});
|
|
57
117
|
});
|
|
@@ -64,7 +124,7 @@ describe('DIVE/scene/root/DIVERoot', () => {
|
|
|
64
124
|
it('should instantiate', () => {
|
|
65
125
|
const root = new DIVERoot();
|
|
66
126
|
expect(root).toBeDefined();
|
|
67
|
-
expect(root.
|
|
127
|
+
expect(root.add).toHaveBeenCalledTimes(4);
|
|
68
128
|
});
|
|
69
129
|
|
|
70
130
|
it('should have Floor', () => {
|
|
@@ -77,6 +137,12 @@ describe('DIVE/scene/root/DIVERoot', () => {
|
|
|
77
137
|
expect(root.Grid).toBeDefined();
|
|
78
138
|
});
|
|
79
139
|
|
|
140
|
+
it('should ComputeSceneBB', () => {
|
|
141
|
+
const root = new DIVERoot();
|
|
142
|
+
const bb = root.ComputeSceneBB();
|
|
143
|
+
expect(bb).toBeDefined();
|
|
144
|
+
});
|
|
145
|
+
|
|
80
146
|
it('should add object', () => {
|
|
81
147
|
const root = new DIVERoot();
|
|
82
148
|
root.AddSceneObject({ entityType: 'light' } as COMLight);
|
package/src/toolbox/BaseTool.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type DraggableEvent = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
16
|
-
export
|
|
16
|
+
export abstract class DIVEBaseTool {
|
|
17
17
|
readonly POINTER_DRAG_THRESHOLD: number = 0.001;
|
|
18
18
|
|
|
19
19
|
public name: string;
|
package/src/toolbox/Toolbox.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import DIVEOrbitControls from "../controls/OrbitControls.ts";
|
|
2
|
-
import DIVEScene from "../scene/Scene.ts";
|
|
3
|
-
import DIVEBaseTool from "./BaseTool.ts";
|
|
4
|
-
import DIVESelectTool from "./select/SelectTool.ts";
|
|
1
|
+
import type DIVEOrbitControls from "../controls/OrbitControls.ts";
|
|
2
|
+
import type DIVEScene from "../scene/Scene.ts";
|
|
3
|
+
import { type DIVEBaseTool } from "./BaseTool.ts";
|
|
4
|
+
import { type DIVESelectTool } from "./select/SelectTool.ts";
|
|
5
|
+
|
|
6
|
+
export type ToolType = 'select' | 'none';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* A Toolbox to activate and deactivate tools to use with the pointer.
|
|
@@ -12,51 +14,51 @@ import DIVESelectTool from "./select/SelectTool.ts";
|
|
|
12
14
|
export default class DIVEToolbox {
|
|
13
15
|
public static readonly DefaultTool = 'select';
|
|
14
16
|
|
|
15
|
-
private
|
|
17
|
+
private _scene: DIVEScene;
|
|
18
|
+
private _controller: DIVEOrbitControls;
|
|
16
19
|
|
|
17
|
-
private
|
|
20
|
+
private _activeTool: DIVEBaseTool | null;
|
|
18
21
|
|
|
19
|
-
private
|
|
22
|
+
private _selectTool: DIVESelectTool | null;
|
|
23
|
+
public get selectTool(): DIVESelectTool {
|
|
24
|
+
if (!this._selectTool) {
|
|
25
|
+
const DIVESelectTool = require('./select/SelectTool.ts').DIVESelectTool as typeof import('./select/SelectTool.ts').DIVESelectTool;
|
|
26
|
+
this._selectTool = new DIVESelectTool(this._scene, this._controller);
|
|
27
|
+
}
|
|
28
|
+
return this._selectTool;
|
|
29
|
+
}
|
|
20
30
|
|
|
21
31
|
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
|
|
22
|
-
this.
|
|
32
|
+
this._scene = scene;
|
|
33
|
+
this._controller = controller;
|
|
23
34
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const pointerUp = this.onPointerUp.bind(this);
|
|
27
|
-
const wheel = this.onWheel.bind(this);
|
|
28
|
-
|
|
29
|
-
controller.domElement.addEventListener('pointermove', pointerMove);
|
|
30
|
-
controller.domElement.addEventListener('pointerdown', pointerDown);
|
|
31
|
-
controller.domElement.addEventListener('pointerup', pointerUp);
|
|
32
|
-
controller.domElement.addEventListener('wheel', wheel);
|
|
33
|
-
|
|
34
|
-
this.removeListenersCallback = () => {
|
|
35
|
-
controller.domElement.removeEventListener('pointermove', pointerMove);
|
|
36
|
-
controller.domElement.removeEventListener('pointerdown', pointerDown);
|
|
37
|
-
controller.domElement.removeEventListener('pointerup', pointerUp);
|
|
38
|
-
controller.domElement.removeEventListener('wheel', wheel);
|
|
39
|
-
};
|
|
35
|
+
// toolset
|
|
36
|
+
this._selectTool = null;
|
|
40
37
|
|
|
41
38
|
// default tool
|
|
42
|
-
this.
|
|
43
|
-
this.activeTool.Activate();
|
|
39
|
+
this._activeTool = null;
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
public
|
|
47
|
-
this.
|
|
42
|
+
public Dispose(): void {
|
|
43
|
+
this.removeEventListeners();
|
|
48
44
|
}
|
|
49
45
|
|
|
50
|
-
public GetActiveTool(): DIVEBaseTool {
|
|
51
|
-
return this.
|
|
46
|
+
public GetActiveTool(): DIVEBaseTool | null {
|
|
47
|
+
return this._activeTool;
|
|
52
48
|
}
|
|
53
49
|
|
|
54
|
-
public UseTool(tool:
|
|
55
|
-
this.
|
|
50
|
+
public UseTool(tool: ToolType): void {
|
|
51
|
+
this._activeTool?.Deactivate();
|
|
56
52
|
switch (tool) {
|
|
57
53
|
case "select": {
|
|
54
|
+
this.addEventListeners();
|
|
58
55
|
this.selectTool.Activate();
|
|
59
|
-
this.
|
|
56
|
+
this._activeTool = this.selectTool;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "none": {
|
|
60
|
+
this.removeEventListeners();
|
|
61
|
+
this._activeTool = null;
|
|
60
62
|
break;
|
|
61
63
|
}
|
|
62
64
|
default: {
|
|
@@ -74,18 +76,32 @@ export default class DIVEToolbox {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
public onPointerMove(e: PointerEvent): void {
|
|
77
|
-
this.
|
|
79
|
+
this._activeTool?.onPointerMove(e);
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
public onPointerDown(e: PointerEvent): void {
|
|
81
|
-
this.
|
|
83
|
+
this._activeTool?.onPointerDown(e);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
public onPointerUp(e: PointerEvent): void {
|
|
85
|
-
this.
|
|
87
|
+
this._activeTool?.onPointerUp(e);
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
public onWheel(e: WheelEvent): void {
|
|
89
|
-
this.
|
|
91
|
+
this._activeTool?.onWheel(e);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private addEventListeners(): void {
|
|
95
|
+
this._controller.domElement.addEventListener('pointermove', (e) => this.onPointerMove(e));
|
|
96
|
+
this._controller.domElement.addEventListener('pointerdown', (e) => this.onPointerDown(e));
|
|
97
|
+
this._controller.domElement.addEventListener('pointerup', (e) => this.onPointerUp(e));
|
|
98
|
+
this._controller.domElement.addEventListener('wheel', (e) => this.onWheel(e));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private removeEventListeners(): void {
|
|
102
|
+
this._controller.domElement.removeEventListener('pointermove', (e) => this.onPointerMove(e));
|
|
103
|
+
this._controller.domElement.removeEventListener('pointerdown', (e) => this.onPointerDown(e));
|
|
104
|
+
this._controller.domElement.removeEventListener('pointerup', (e) => this.onPointerUp(e));
|
|
105
|
+
this._controller.domElement.removeEventListener('wheel', (e) => this.onWheel(e));
|
|
90
106
|
}
|
|
91
107
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
|
|
2
|
+
import { DIVEBaseTool } from '../BaseTool';
|
|
3
|
+
import type DIVEOrbitControls from '../../controls/OrbitControls';
|
|
4
|
+
import type DIVEScene from '../../scene/Scene';
|
|
2
5
|
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
6
|
import { type DIVEHoverable } from '../../interface/Hoverable';
|
|
8
|
-
import { DIVEDraggable } from '../../interface/Draggable';
|
|
7
|
+
import { type DIVEDraggable } from '../../interface/Draggable';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* @jest-environment jsdom
|
|
@@ -47,8 +46,18 @@ describe('dive/toolbox/DIVEBaseTool', () => {
|
|
|
47
46
|
});
|
|
48
47
|
|
|
49
48
|
it('should instantiate', () => {
|
|
50
|
-
const
|
|
51
|
-
expect(
|
|
49
|
+
const baseTool = new abstractWrapper(mockScene, mockController);
|
|
50
|
+
expect(baseTool).toBeDefined();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should Activate', () => {
|
|
54
|
+
const baseTool = new abstractWrapper(mockScene, mockController);
|
|
55
|
+
expect(() => baseTool.Activate()).not.toThrow();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should Deactivate', () => {
|
|
59
|
+
const baseTool = new abstractWrapper(mockScene, mockController);
|
|
60
|
+
expect(() => baseTool.Deactivate()).not.toThrow();
|
|
52
61
|
});
|
|
53
62
|
|
|
54
63
|
it('should raycast', () => {
|
|
@@ -63,7 +72,24 @@ describe('dive/toolbox/DIVEBaseTool', () => {
|
|
|
63
72
|
expect(toolBox['_pointerAnyDown']).toBeDefined();
|
|
64
73
|
expect(toolBox['_pointerAnyDown']).toBe(false);
|
|
65
74
|
|
|
75
|
+
toolBox['_pointerPrimaryDown'] = false;
|
|
76
|
+
toolBox['_pointerMiddleDown'] = false;
|
|
77
|
+
toolBox['_pointerSecondaryDown'] = false;
|
|
78
|
+
expect(toolBox['_pointerAnyDown']).toBe(false);
|
|
79
|
+
|
|
66
80
|
toolBox['_pointerPrimaryDown'] = true;
|
|
81
|
+
toolBox['_pointerMiddleDown'] = false;
|
|
82
|
+
toolBox['_pointerSecondaryDown'] = false;
|
|
83
|
+
expect(toolBox['_pointerAnyDown']).toBe(true);
|
|
84
|
+
|
|
85
|
+
toolBox['_pointerPrimaryDown'] = false;
|
|
86
|
+
toolBox['_pointerMiddleDown'] = true;
|
|
87
|
+
toolBox['_pointerSecondaryDown'] = false;
|
|
88
|
+
expect(toolBox['_pointerAnyDown']).toBe(true);
|
|
89
|
+
|
|
90
|
+
toolBox['_pointerPrimaryDown'] = false;
|
|
91
|
+
toolBox['_pointerMiddleDown'] = false;
|
|
92
|
+
toolBox['_pointerSecondaryDown'] = true;
|
|
67
93
|
expect(toolBox['_pointerAnyDown']).toBe(true);
|
|
68
94
|
});
|
|
69
95
|
|
|
@@ -388,8 +414,18 @@ describe('dive/toolbox/DIVEBaseTool', () => {
|
|
|
388
414
|
expect(() => toolBox.onDrag({} as PointerEvent)).not.toThrow();
|
|
389
415
|
});
|
|
390
416
|
|
|
417
|
+
it('should execute onCLick correctly', () => {
|
|
418
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
419
|
+
expect(() => toolBox.onClick({} as PointerEvent)).not.toThrow();
|
|
420
|
+
});
|
|
421
|
+
|
|
391
422
|
it('should execute onDragEnd correctly', () => {
|
|
392
423
|
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
393
424
|
expect(() => toolBox.onDragEnd({} as PointerEvent)).not.toThrow();
|
|
394
425
|
});
|
|
426
|
+
|
|
427
|
+
it('should execute onWheel correctly', () => {
|
|
428
|
+
const toolBox = new abstractWrapper(mockScene, mockController);
|
|
429
|
+
expect(() => toolBox.onWheel({} as WheelEvent)).not.toThrow();
|
|
430
|
+
});
|
|
395
431
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import DIVEToolbox, { type ToolType } from '../Toolbox';
|
|
2
|
+
import type DIVEOrbitControls from '../../controls/OrbitControls';
|
|
3
|
+
import type DIVEScene from '../../scene/Scene';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @jest-environment jsdom
|
|
@@ -21,27 +21,20 @@ const mock_Canvas = {
|
|
|
21
21
|
offsetTop: 0,
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const mock_Activate = jest.fn();
|
|
25
|
-
const mock_Deactivate = jest.fn();
|
|
26
|
-
const mock_onPointerDown = jest.fn();
|
|
27
|
-
const mock_onPointerMove = jest.fn();
|
|
28
|
-
const mock_onPointerUp = jest.fn();
|
|
29
|
-
const mock_onWheel = jest.fn();
|
|
30
|
-
const mock_SetGizmoMode = jest.fn();
|
|
31
|
-
const mock_SetGizmoVisibility = jest.fn();
|
|
32
|
-
|
|
33
24
|
jest.mock('../select/SelectTool.ts', () => {
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
return {
|
|
26
|
+
DIVESelectTool: jest.fn(function () {
|
|
27
|
+
this.Activate = jest.fn();
|
|
28
|
+
this.Deactivate = jest.fn();
|
|
29
|
+
this.onPointerDown = jest.fn();
|
|
30
|
+
this.onPointerMove = jest.fn();
|
|
31
|
+
this.onPointerUp = jest.fn();
|
|
32
|
+
this.onWheel = jest.fn();
|
|
33
|
+
this.SetGizmoMode = jest.fn();
|
|
34
|
+
this.SetGizmoVisibility = jest.fn();
|
|
35
|
+
return this;
|
|
36
|
+
})
|
|
37
|
+
}
|
|
45
38
|
});
|
|
46
39
|
|
|
47
40
|
const mockController = {
|
|
@@ -58,52 +51,56 @@ describe('dive/toolbox/DIVEToolBox', () => {
|
|
|
58
51
|
it('should instantiate', () => {
|
|
59
52
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
60
53
|
expect(toolBox).toBeDefined();
|
|
61
|
-
expect(mock_Activate).toHaveBeenCalledTimes(1);
|
|
62
|
-
expect(mock_addEventListener).toHaveBeenCalled();
|
|
63
54
|
});
|
|
64
55
|
|
|
65
56
|
it('should dispose', () => {
|
|
66
57
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
67
|
-
toolBox.
|
|
58
|
+
toolBox.Dispose();
|
|
68
59
|
expect(mock_removeEventListener).toHaveBeenCalled();
|
|
69
60
|
});
|
|
70
61
|
|
|
71
62
|
it('should throw with incorrect tool', () => {
|
|
72
63
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
73
|
-
expect(() => toolBox.UseTool('not a real tool')).toThrow();
|
|
74
|
-
|
|
64
|
+
expect(() => toolBox.UseTool('not a real tool' as unknown as ToolType)).toThrow();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should use no tool', () => {
|
|
68
|
+
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
69
|
+
expect(() => toolBox.UseTool('select')).not.toThrow();
|
|
70
|
+
expect(() => toolBox.UseTool('none')).not.toThrow();
|
|
75
71
|
});
|
|
76
72
|
|
|
77
73
|
it('should use select tool', () => {
|
|
78
74
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
79
|
-
expect(
|
|
80
|
-
toolBox.UseTool(DIVEToolbox.DefaultTool);
|
|
81
|
-
expect(mock_Deactivate).toHaveBeenCalledTimes(1);
|
|
82
|
-
expect(mock_Activate).toHaveBeenCalledTimes(2);
|
|
75
|
+
expect(() => toolBox.UseTool(DIVEToolbox.DefaultTool)).not.toThrow();
|
|
83
76
|
});
|
|
84
77
|
|
|
85
78
|
it('should execute pointer down event on tool', () => {
|
|
86
79
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
87
|
-
toolBox.onPointerDown({ type: 'pointerdown' } as PointerEvent);
|
|
88
|
-
expect(
|
|
80
|
+
expect(() => toolBox.onPointerDown({ type: 'pointerdown' } as PointerEvent)).not.toThrow();
|
|
81
|
+
expect(() => toolBox.UseTool('select')).not.toThrow();
|
|
82
|
+
expect(() => toolBox.onPointerDown({ type: 'pointerdown' } as PointerEvent)).not.toThrow();
|
|
89
83
|
});
|
|
90
84
|
|
|
91
85
|
it('should execute pointer move event on tool', () => {
|
|
92
86
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
93
|
-
toolBox.onPointerMove({ type: 'pointermove' } as PointerEvent);
|
|
94
|
-
expect(
|
|
87
|
+
expect(() => toolBox.onPointerMove({ type: 'pointermove' } as PointerEvent)).not.toThrow();
|
|
88
|
+
expect(() => toolBox.UseTool('select')).not.toThrow();
|
|
89
|
+
expect(() => toolBox.onPointerMove({ type: 'pointermove' } as PointerEvent)).not.toThrow();
|
|
95
90
|
});
|
|
96
91
|
|
|
97
92
|
it('should execute pointer up event on tool', () => {
|
|
98
93
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
99
|
-
toolBox.onPointerUp({ type: 'pointerup' } as PointerEvent);
|
|
100
|
-
expect(
|
|
94
|
+
expect(() => toolBox.onPointerUp({ type: 'pointerup' } as PointerEvent)).not.toThrow();
|
|
95
|
+
expect(() => toolBox.UseTool('select')).not.toThrow();
|
|
96
|
+
expect(() => toolBox.onPointerUp({ type: 'pointerup' } as PointerEvent)).not.toThrow();
|
|
101
97
|
});
|
|
102
98
|
|
|
103
99
|
it('should execute wheel event on tool', () => {
|
|
104
100
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
105
|
-
toolBox.onWheel({ type: 'wheel' } as WheelEvent);
|
|
106
|
-
expect(
|
|
101
|
+
expect(() => toolBox.onWheel({ type: 'wheel' } as WheelEvent)).not.toThrow();
|
|
102
|
+
expect(() => toolBox.UseTool('select')).not.toThrow();
|
|
103
|
+
expect(() => toolBox.onWheel({ type: 'wheel' } as WheelEvent)).not.toThrow();
|
|
107
104
|
});
|
|
108
105
|
|
|
109
106
|
it('should get active tool', () => {
|
|
@@ -113,13 +110,11 @@ describe('dive/toolbox/DIVEToolBox', () => {
|
|
|
113
110
|
|
|
114
111
|
it('should set gizmo mode', () => {
|
|
115
112
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
116
|
-
toolBox.SetGizmoMode('translate');
|
|
117
|
-
expect(mock_SetGizmoMode).toHaveBeenCalledTimes(1);
|
|
113
|
+
expect(() => toolBox.SetGizmoMode('translate')).not.toThrow();
|
|
118
114
|
});
|
|
119
115
|
|
|
120
116
|
it('should set gizmo active', () => {
|
|
121
117
|
const toolBox = new DIVEToolbox({} as DIVEScene, mockController);
|
|
122
|
-
toolBox.SetGizmoVisibility(true);
|
|
123
|
-
expect(mock_SetGizmoVisibility).toHaveBeenCalledTimes(1);
|
|
118
|
+
expect(() => toolBox.SetGizmoVisibility(true)).not.toThrow();
|
|
124
119
|
});
|
|
125
120
|
});
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { Object3D } from "three";
|
|
2
|
-
import { DIVESelectable, isSelectable } from "../../interface/Selectable.ts";
|
|
1
|
+
import { type Object3D } from "three";
|
|
3
2
|
import DIVEScene from "../../scene/Scene.ts";
|
|
4
|
-
import { DIVEMoveable } from "../../interface/Moveable.ts";
|
|
5
|
-
import DIVEOrbitControls from "../../controls/OrbitControls.ts";
|
|
6
3
|
import DIVETransformTool from "../transform/TransformTool.ts";
|
|
4
|
+
import type DIVEOrbitControls from "../../controls/OrbitControls.ts";
|
|
5
|
+
import { type DIVESelectable, findSelectableInterface } from "../../interface/Selectable.ts";
|
|
6
|
+
import { type DIVEMoveable } from "../../interface/Moveable.ts";
|
|
7
|
+
import { type DIVEBaseTool } from "../BaseTool.ts";
|
|
8
|
+
|
|
9
|
+
export const isSelectTool = (tool: DIVEBaseTool): tool is DIVESelectTool => {
|
|
10
|
+
return (tool as DIVESelectTool).isSelectTool !== undefined;
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
export interface DIVEObjectEventMap {
|
|
9
14
|
select: object
|
|
@@ -17,7 +22,8 @@ export interface DIVEObjectEventMap {
|
|
|
17
22
|
* @module
|
|
18
23
|
*/
|
|
19
24
|
|
|
20
|
-
export
|
|
25
|
+
export class DIVESelectTool extends DIVETransformTool {
|
|
26
|
+
readonly isSelectTool: boolean = true;
|
|
21
27
|
|
|
22
28
|
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
|
|
23
29
|
super(scene, controller);
|
|
@@ -39,10 +45,6 @@ export default class DIVESelectTool extends DIVETransformTool {
|
|
|
39
45
|
this.DetachGizmo();
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
public DetachGizmo(): void {
|
|
43
|
-
this._gizmo.detach();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
48
|
public AttachGizmo(selectable: DIVESelectable): void {
|
|
47
49
|
if ('isMoveable' in selectable) {
|
|
48
50
|
const movable = selectable as (Object3D & DIVESelectable & DIVEMoveable);
|
|
@@ -51,11 +53,15 @@ export default class DIVESelectTool extends DIVETransformTool {
|
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
public DetachGizmo(): void {
|
|
57
|
+
this._gizmo.detach();
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
public onClick(e: PointerEvent): void {
|
|
55
61
|
super.onClick(e);
|
|
56
62
|
|
|
57
|
-
const first = this._raycaster.intersectObjects(this._scene.Root.children, true).filter((intersect) => intersect.object.visible
|
|
58
|
-
const selectable =
|
|
63
|
+
const first = this._raycaster.intersectObjects(this._scene.Root.children, true).filter((intersect) => intersect.object.visible)[0];
|
|
64
|
+
const selectable = findSelectableInterface(first?.object);
|
|
59
65
|
|
|
60
66
|
// if nothing is hit
|
|
61
67
|
if (!first || !selectable) {
|
|
@@ -77,21 +83,4 @@ export default class DIVESelectTool extends DIVETransformTool {
|
|
|
77
83
|
// select clicked object
|
|
78
84
|
this.Select(selectable);
|
|
79
85
|
}
|
|
80
|
-
|
|
81
|
-
private findSelectableInterface(child: Object3D): (Object3D & DIVESelectable) | undefined {
|
|
82
|
-
if (child === undefined) return undefined;
|
|
83
|
-
|
|
84
|
-
if (child.parent === null) {
|
|
85
|
-
// in this case it is the scene itself
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (isSelectable(child)) {
|
|
90
|
-
// in this case it is the Selectable
|
|
91
|
-
return child;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// search recursively in parent
|
|
95
|
-
return this.findSelectableInterface(child.parent);
|
|
96
|
-
}
|
|
97
86
|
}
|