@shopware-ag/dive
Version:
Shopware Spatial Framework
167 lines (138 loc) • 5.33 kB
text/typescript
import { DIVEBaseTool } from '../BaseTool.ts';
import { type DIVEScene } from '../../scene/Scene.ts';
import type DIVEOrbitControls from '../../controls/OrbitControls.ts';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';
import { type DIVEMovable } from '../../interface/Movable.ts';
import { implementsInterface } from '../../helper/isInterface/implementsInterface.ts';
import { DIVEGizmo } from '../../gizmo/Gizmo.ts';
import { type Mesh, type MeshBasicMaterial } from 'three';
import {
AxesColorBlue,
AxesColorGreen,
AxesColorRed,
} from '../../constant/AxisHelperColors.ts';
export const isTransformTool = (
tool: DIVEBaseTool,
): tool is DIVETransformTool => {
return (tool as DIVETransformTool).isTransformTool !== undefined;
};
export interface DIVEObjectEventMap {
select: object;
}
/**
* A Tool to select and move objects in the scene.
*
* Objects have to implement the DIVESelectable interface to be selectable and DIVEMovable to be movable.
*
* @module
*/
export default class DIVETransformTool extends DIVEBaseTool {
readonly isTransformTool: boolean = true;
private _scaleLinked: boolean;
protected _gizmo: TransformControls | DIVEGizmo;
constructor(scene: DIVEScene, controller: DIVEOrbitControls) {
super(scene, controller);
this.name = 'DIVETransformTool';
this._scaleLinked = false;
this._gizmo = this.initGizmo() as TransformControls;
this._scene.add(this._gizmo);
}
public Activate(): void {}
public SetGizmoMode(mode: 'translate' | 'rotate' | 'scale'): void {
this._gizmo.mode = mode;
}
public SetGizmoVisibility(active: boolean): void {
const contains = this._scene.children.includes(this._gizmo);
if (active && !contains) {
this._scene.add(this._gizmo);
if ('isTransformControls' in this._gizmo) {
(this._gizmo as TransformControls)
.getRaycaster()
.layers.enableAll();
}
} else if (!active && contains) {
this._scene.remove(this._gizmo);
if ('isTransformControls' in this._gizmo) {
(this._gizmo as TransformControls)
.getRaycaster()
.layers.disableAll();
}
}
}
public SetGizmoScaleLinked(linked: boolean): void {
this._scaleLinked = linked;
}
// only used for optimizing pointer events with DIVEGizmo
// public onPointerDown(e: PointerEvent): void {
// super.onPointerDown(e);
// if (this._hovered) {
// this._dragRaycastOnObjects = (
// this._gizmo as DIVEGizmo
// ).gizmoPlane?.children;
// }
// }
// only used for optimizing pointer events with DIVEGizmo
// protected raycast(): Intersection[] {
// return super.raycast((this._gizmo as DIVEGizmo).gizmoNode.children);
// }
private initGizmo(): TransformControls | DIVEGizmo {
const g = new TransformControls(
// this._controller,
this._controller.object,
this._controller.domElement,
);
// g.debug = true;
g.mode = 'translate';
g.traverse((child) => {
if (!('isMesh' in child)) return;
const material = (child as Mesh).material as MeshBasicMaterial;
if (child.name === 'X') {
material.color.set(AxesColorRed);
}
if (child.name === 'Y') {
material.color.set(AxesColorGreen);
}
if (child.name === 'Z') {
material.color.set(AxesColorBlue);
}
if (child.name === 'XY') {
material.color.set(AxesColorBlue);
}
if (child.name === 'YZ') {
material.color.set(AxesColorRed);
}
if (child.name === 'XZ') {
material.color.set(AxesColorGreen);
}
});
// happens when pointerDown event is called on gizmo
g.addEventListener('mouseDown', () => {
this._controller.enabled = false;
if (!implementsInterface<DIVEMovable>(g.object, 'isMovable'))
return;
if (!g.object.onMoveStart) return;
g.object.onMoveStart();
});
// happens when pointerMove event is called on gizmo
g.addEventListener('objectChange', () => {
if (!implementsInterface<DIVEMovable>(g.object, 'isMovable'))
return;
if (!g.object.onMove) return;
g.object.onMove();
if (this._scaleLinked) {
const scale = g.object.scale;
const averageScale = (scale.x + scale.y + scale.z) / 3;
g.object.scale.set(averageScale, averageScale, averageScale);
}
});
// happens when pointerUp event is called on gizmo
g.addEventListener('mouseUp', () => {
this._controller.enabled = true;
if (!implementsInterface<DIVEMovable>(g.object, 'isMovable'))
return;
if (!g.object.onMoveEnd) return;
g.object.onMoveEnd();
});
return g;
}
}