From d3ade02a95fd537fd25c055c8dc982a590e6345a Mon Sep 17 00:00:00 2001 From: luoyifan Date: Fri, 6 Jun 2025 20:36:58 +0800 Subject: [PATCH] =?UTF-8?q?EsDragControl=20=E5=BB=B6=E8=BF=9F=E6=8A=93?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/controls/DragControl.ts | 82 +++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/src/core/controls/DragControl.ts b/src/core/controls/DragControl.ts index 21654e5..f6dbe0a 100644 --- a/src/core/controls/DragControl.ts +++ b/src/core/controls/DragControl.ts @@ -11,24 +11,34 @@ export default class DragControl implements IControls { private viewport: Viewport private _is_enabled: boolean = true private domElement: HTMLElement - public isDragging: boolean = false private isPointerDown: boolean = false private dragStartMouse: THREE.Vector2 = new THREE.Vector2() private checkStateInterval: number | null = null private dragShadowsGroup: THREE.Group | null = null private dragDelayTimeout: number | null = null + + private static readonly SHADOW_MATERIAL = new THREE.MeshBasicMaterial({ + color: 0x222222, + transparent: true, + opacity: 0.5, + depthWrite: false, + side: THREE.DoubleSide + }) + + public isDragging: boolean = false + init(viewport: Viewport): void { this.viewport = viewport - const domElement = this.viewport.renderer.domElement + this.domElement = domElement + domElement.addEventListener('pointerdown', this.onPointerDown) domElement.addEventListener('pointermove', this.onPointerMove) domElement.addEventListener('pointerup', this.onPointerUp) domElement.addEventListener('pointerleave', this.onPointerLeave) domElement.style.cursor = 'auto' - this.domElement = domElement } @@ -41,12 +51,10 @@ export default class DragControl implements IControls { this.domElement.removeEventListener('pointerdown', this.onPointerDown) this.domElement.removeEventListener('pointerup', this.onPointerUp) this.domElement.removeEventListener('pointerleave', this.onPointerLeave) - - this.cleanupDrag() - this.domElement.style.cursor = 'auto' - this.viewport = null } + this.cleanupDrag() + this.viewport = null } /** @@ -57,35 +65,29 @@ export default class DragControl implements IControls { const mouse = this.getMousePosition(event.clientX, event.clientY) const intersected = this.getIntersectedDraggableObject(mouse) + if (!intersected) return + this.viewport.controls.enabled = false // 设置定时器:0.1秒后才抓取拖拽 this.dragDelayTimeout = window.setTimeout(() => { - - const mouse = this.getMousePosition(event.clientX, event.clientY) - const intersected = this.getIntersectedDraggableObject(mouse) - if (!intersected) return - this.isPointerDown = true this.dragStartMouse.set(intersected.position.x, intersected.position.z) let selectedObjects = [intersected] - if (this.viewport.state.multiSelectedObjects.length > 0) { - if (this.viewport.state.multiSelectedObjects.includes(intersected)) { - // drag multi-selected objects - selectedObjects = this.viewport.state.multiSelectedObjects - } + const multiSelected = this.viewport.state.multiSelectedObjects + if (multiSelected.length > 0 && multiSelected.includes(intersected)) { + selectedObjects = multiSelected } + this.createShadows(selectedObjects) + this.domElement.style.cursor = 'grabbing' this.checkStateInterval = setInterval(() => { if (isNaN(CurrentMouseInfo.x) || isNaN(CurrentMouseInfo.z) || !this.isPointerDown) { this.cancelDrag() } - }, 100) - - this.createShadows(selectedObjects) - this.domElement.style.cursor = 'grabbing' + }, 100) // 每100毫秒检查一次状态, 鼠标移出要主动清理 }, 100) // 0.1秒延迟抓取 @@ -100,30 +102,25 @@ export default class DragControl implements IControls { if (!isNaN(this.dragStartMouse.x) && !isNaN(this.dragStartMouse.y) && this.dragShadowsGroup) { this.isDragging = true this.domElement.style.cursor = 'grabbing' - - // 更新阴影位置(锁定 Y 轴) this.updateShadows(new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z)) } else { const mouse = this.getMousePosition(event.clientX, event.clientY) const intersected = this.getIntersectedDraggableObject(mouse) - if (intersected) { - this.domElement.style.cursor = 'grab' - } else { - this.domElement.style.cursor = 'auto' - } + this.domElement.style.cursor = intersected ? 'grab' : 'auto' } } + /** * pointerup 事件处理 */ private onPointerUp = (event: PointerEvent): void => { if (this.isDragging) { - const startPos = this.dragStartMouse + const startPos = this.dragStartMouse.clone() const targetPos = new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z) - if (startPos && targetPos) { + if (startPos && targetPos && !_.isNaN(startPos.x) && !_.isNaN(startPos.y)) { this.dragComplete(startPos, targetPos) } } @@ -139,16 +136,16 @@ export default class DragControl implements IControls { this.domElement.style.cursor = 'auto' } - if (this.viewport) { - this.viewport.controls.enabled = true - } - this.isDragging = false this.isPointerDown = false this.dragStartMouse.set(NaN, NaN) this.removeShadows() + if (this.viewport) { + this.viewport.controls.enabled = true + } + if (this.dragDelayTimeout !== null) { clearTimeout(this.dragDelayTimeout) this.dragDelayTimeout = null @@ -186,13 +183,6 @@ export default class DragControl implements IControls { } } - private static readonly SHADOW_MATERIAL = new THREE.MeshBasicMaterial({ - color: 0x222222, - transparent: true, - opacity: 0.5, - depthWrite: false, - side: THREE.DoubleSide - }) /** * 创建拖拽阴影 @@ -200,15 +190,11 @@ export default class DragControl implements IControls { private createShadows(objects: THREE.Object3D[]): void { this.removeShadows() - console.log('createShadows', objects.map(obj => obj.name)) - this.dragShadowsGroup = new THREE.Group() - // 初始位置为 (0, 0, 0) - this.dragShadowsGroup.position.set(0, 0, 0) for (const obj of objects) { - if (!obj.userData.entityId) { - console.error('Object does not have entityId:', obj.name) - continue // 跳过没有 entityId 的对象 + if (_.isNil(_.get(obj, 'userData.entityId'))) { + console.error(`Object ${obj.name} missing entityId`) + continue } // 克隆对象的几何体和材质