@shopware-ag/dive
Version:
Shopware Spatial Framework
196 lines (169 loc) • 5.52 kB
text/typescript
import {
BoxGeometry,
Color,
ColorRepresentation,
CylinderGeometry,
Mesh,
MeshBasicMaterial,
Object3D,
Vector3,
} from 'three';
import { UI_LAYER_MASK } from '../../constant/VisibilityLayerMask';
import { DIVEHoverable } from '../../interface/Hoverable';
import { DIVEScaleGizmo } from '../scale/ScaleGizmo';
import { DIVEDraggable } from '../../interface/Draggable';
import { DraggableEvent } from '../../toolbox/BaseTool';
export class DIVEScaleHandle
extends Object3D
implements DIVEHoverable, DIVEDraggable
{
readonly isHoverable: true = true;
readonly isDraggable: true = true;
public set debug(value: boolean) {
this._colliderMesh.visible = value;
}
public parent: DIVEScaleGizmo | null = null;
public axis: 'x' | 'y' | 'z';
private _color: Color = new Color(0xff00ff);
private _colorHover: Color;
private _hovered: boolean;
private _highlight: boolean;
public get highlight(): boolean {
return this._highlight;
}
public set highlight(highlight: boolean) {
this._highlight = highlight;
this._lineMaterial.color =
this._highlight || this._hovered ? this._colorHover : this._color;
}
private _lineMaterial: MeshBasicMaterial;
private _colliderMesh: Mesh;
private _box: Mesh;
private _boxSize: number;
public get forwardVector(): Vector3 {
return new Vector3(0, 0, 1)
.applyQuaternion(this.quaternion)
.normalize();
}
public get rightVector(): Vector3 {
return new Vector3(1, 0, 0)
.applyQuaternion(this.quaternion)
.normalize();
}
public get upVector(): Vector3 {
return new Vector3(0, 1, 0)
.applyQuaternion(this.quaternion)
.normalize();
}
constructor(
axis: 'x' | 'y' | 'z',
length: number,
direction: Vector3,
color: ColorRepresentation,
boxSize: number = 0.05,
) {
super();
this.name = 'DIVEScaleHandle';
this.axis = axis;
this._color.set(color);
this._colorHover = this._color.clone().multiplyScalar(2);
this._hovered = false;
this._highlight = false;
this._boxSize = boxSize;
// create line
const lineGeo = new CylinderGeometry(
0.01,
0.01,
length - boxSize / 2,
13,
);
this._lineMaterial = new MeshBasicMaterial({
color: color,
depthTest: false,
depthWrite: false,
});
const lineMesh = new Mesh(lineGeo, this._lineMaterial);
lineMesh.layers.mask = UI_LAYER_MASK;
lineMesh.renderOrder = Infinity;
lineMesh.rotateX(Math.PI / 2);
lineMesh.translateY(length / 2 - boxSize / 4);
this.add(lineMesh);
// create box
this._box = new Mesh(
new BoxGeometry(boxSize, boxSize, boxSize),
this._lineMaterial,
);
this._box.layers.mask = UI_LAYER_MASK;
this._box.renderOrder = Infinity;
this._box.rotateX(Math.PI / 2);
this._box.translateY(length - boxSize / 2);
this._box.rotateZ((direction.x * Math.PI) / 2);
this._box.rotateX((direction.z * Math.PI) / 2);
this.add(this._box);
// create collider
const colliderGeo = new CylinderGeometry(
0.1,
0.1,
length + boxSize / 2,
3,
);
const colliderMaterial = new MeshBasicMaterial({
color: 0xff00ff,
transparent: true,
opacity: 0.15,
depthTest: false,
depthWrite: false,
});
this._colliderMesh = new Mesh(colliderGeo, colliderMaterial);
this._colliderMesh.visible = false;
this._colliderMesh.layers.mask = UI_LAYER_MASK;
this._colliderMesh.renderOrder = Infinity;
this._colliderMesh.rotateX(Math.PI / 2);
this._colliderMesh.translateY(length / 2);
this.add(this._colliderMesh);
this.rotateX((direction.y * -Math.PI) / 2);
this.rotateY((direction.x * Math.PI) / 2);
}
public reset(): void {
this._lineMaterial.color = this._color;
}
public update(scale: Vector3): void {
this._box.scale.copy(
new Vector3(1, 1, 1) // identity scale ...
.sub(this.forwardVector) // subtracted the forward vector ...
.add(
// to then add ...
scale
.clone() // the scale ...
.multiply(this.forwardVector), // that is scaled by the forward vector again to get the forward vector as the only direction
),
);
}
public onPointerEnter(): void {
this._hovered = true;
if (this.parent) {
this.parent.onHoverAxis(this, true);
}
}
public onPointerLeave(): void {
this._hovered = false;
if (this.parent) {
this.parent.onHoverAxis(this, false);
}
}
public onDragStart(): void {
if (this.parent) {
this.parent.onAxisDragStart(this);
}
}
public onDrag(e: DraggableEvent): void {
if (this.parent) {
this.parent.onAxisDrag(this, e);
}
}
public onDragEnd(): void {
if (this.parent) {
this.parent.onAxisDragEnd(this);
}
}
}