|
|
|
@ -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 |
|
|
|
} |
|
|
|
|
|
|
|
// 克隆对象的几何体和材质
|
|
|
|
|