UNPKG

@shopware-ag/dive

Version:

Shopware Spatial Framework

196 lines (169 loc) 5.52 kB
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); } } }