Browse Source

EsDragControl2 拖拽管理器完成

master
修宁 6 months ago
parent
commit
e85311a709
  1. 4
      src/core/base/BaseRenderer.ts
  2. 265
      src/core/controls/EsDragControl2.ts
  3. 28
      src/core/engine/Viewport.ts
  4. 2
      src/model/itemType/ItemType.ts
  5. 2
      src/model/itemType/Toolbox.ts
  6. 29
      src/modules/gstore/GstoreRenderer.ts
  7. 2
      src/modules/measure/MeasureRenderer.ts
  8. 2
      src/modules/way/WayRenderer.ts

4
src/core/base/BaseRenderer.ts

@ -124,7 +124,7 @@ export default abstract class BaseRenderer {
this.tempViewport.scene.add(...objects)
const dragObjects = objects.filter(obj => !!obj.userData.draggable)
this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
//this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
}
removeFromScene(...objects: THREE.Object3D[]) {
@ -133,7 +133,7 @@ export default abstract class BaseRenderer {
return
}
this.tempViewport.scene.remove(...objects)
this.tempViewport.dragControl.setDragObjects(objects, 'remove')
//this.tempViewport.dragControl.setDragObjects(objects, 'remove')
}
/**

265
src/core/controls/EsDragControl2.ts

@ -0,0 +1,265 @@
import * as THREE from 'three'
import type Viewport from '@/core/engine/Viewport.ts'
import type IControls from '@/core/controls/IControls.ts'
import { Curve } from 'three'
import { getClosestObject } from '@/core/ModelUtils.ts'
import EventBus from '@/runtime/EventBus.ts'
/**
* DragControl2 - ThreeJS X/Z
*/
export default class DragControl2 implements IControls {
private viewport: Viewport
private enabled: boolean = true
private isDragging: boolean = false
private isPointerDown: boolean = false
private dragStartMouse: THREE.Vector2 = new THREE.Vector2()
private dragShadows: THREE.Group | null = null
init(viewport: Viewport): void {
this.viewport = viewport
const domElement = this.viewport.renderer.domElement
domElement.addEventListener('pointermove', this.onPointerMove)
domElement.addEventListener('pointerdown', this.onPointerDown)
domElement.addEventListener('pointerup', this.onPointerUp)
domElement.addEventListener('pointerleave', this.onPointerLeave)
domElement.style.cursor = 'auto'
}
/**
* /
*/
set enable(value: boolean) {
this.enabled = value
if (!value) {
this.cleanupDrag()
}
}
get enable(): boolean {
return this.enabled
}
/**
*
*/
dispose(): void {
const domElement = this.viewport.renderer.domElement
domElement.removeEventListener('pointermove', this.onPointerMove)
domElement.removeEventListener('pointerdown', this.onPointerDown)
domElement.removeEventListener('pointerup', this.onPointerUp)
domElement.removeEventListener('pointerleave', this.onPointerLeave)
this.cleanupDrag()
domElement.style.cursor = 'auto'
}
/**
*
*/
private cleanupDrag(): void {
if (this.isDragging || this.isPointerDown) {
this.isDragging = false
this.isPointerDown = false
this.dragStartMouse.set(NaN, NaN)
this.removeShadows()
}
}
/**
*
*/
private getMousePosition(clientX: number, clientY: number): THREE.Vector2 {
const rect = this.viewport.renderer.domElement.getBoundingClientRect()
return new THREE.Vector2(
((clientX - rect.left) / rect.width) * 2 - 1,
((clientY - rect.top) / rect.height) * -2 + 1
)
}
/**
* 线
*/
private getIntersectedDraggableObject(mouse: THREE.Vector2): THREE.Object3D | null {
const raycaster = new THREE.Raycaster()
raycaster.setFromCamera(mouse, this.viewport.camera)
const draggableObjects = this.viewport.entityManager._draggableObjects || []
const intersects = raycaster.intersectObjects(draggableObjects, true)
if (intersects.length > 0) {
return getClosestObject(intersects[0].object)
}
}
/**
*
*/
private createShadows(objects: THREE.Object3D[]): void {
this.removeShadows()
console.log('createShadows', objects.map(obj => obj.name))
this.dragShadows = new THREE.Group()
for (const obj of objects) {
if (!obj.userData.entityId) {
console.error('Object does not have entityId:', obj.name)
continue // 跳过没有 entityId 的对象
}
const shadow = obj.clone()
shadow.userData = {
isShadow: true,
entityId: obj.userData.entityId,
originPosition: obj.position.clone() // 保存原始位置
}
this.dragShadows.add(shadow)
}
this.viewport.scene.add(this.dragShadows)
}
/**
*
*/
private removeShadows(): void {
if (this.dragShadows) {
this.viewport.scene.remove(this.dragShadows)
this.dragShadows = null
}
}
/**
* X/Z
*/
private updateShadows(newPosition: THREE.Vector2): void {
if (!this.dragShadows) return
// 计算新位置与拖拽开始位置的偏移量
const offsetX = newPosition.x - this.dragStartMouse.x
const offsetZ = newPosition.y - this.dragStartMouse.y
this.dragShadows.children.forEach((shadow, index) => {
const newPosX = shadow.userData.originPosition.x + offsetX
const newPosZ = shadow.userData.originPosition.z + offsetZ
shadow.position.set(newPosX, shadow.userData.originPosition.y, newPosZ) // 锁定 Y 轴高度
console.log(`Updated shadow position for ${shadow.name}:`, shadow.position)
})
}
private dragComplete = (startPos: THREE.Vector2, targetPos: THREE.Vector2): void => {
// console.log(`Drag completed from ${startPos.toArray()} to ${targetPos.toArray()}`)
this.viewport.stateManager.beginStateUpdate()
for (const object of this.dragShadows.children) {
const entityId = object.userData.entityId
if (entityId) {
const entity = this.viewport.stateManager.findItemById(entityId)
if (entity) {
// 更新实体位置
entity.tf[0][0] = object.position.x
entity.tf[0][2] = object.position.z
} else {
system.showErrorDialog('not found entityId:' + entityId)
}
} else {
system.showErrorDialog('not found entity')
}
}
this.viewport.stateManager.endStateUpdate()
EventBus.dispatch('multiselectedObjectChanged', {
multiSelectedObjects: this.viewport.state.multiSelectedObjects
})
EventBus.dispatch('selectedObjectPropertyChanged', {})
this.cleanupDrag()
}
/**
* pointermove
*/
private onPointerMove = (event: PointerEvent): void => {
if (!this.enabled) return
if (!isNaN(this.dragStartMouse.x) && !isNaN(this.dragStartMouse.y) && this.dragShadows) {
this.isDragging = true
// 更新鼠标样式
this.viewport.renderer.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.viewport.renderer.domElement.style.cursor = 'grab'
} else {
this.viewport.renderer.domElement.style.cursor = 'auto'
}
}
}
/**
* pointerdown
*/
private onPointerDown = (event: PointerEvent): void => {
if (!this.enabled) return
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)
this.viewport.controls.enabled = false
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
}
}
this.createShadows(selectedObjects)
}
/**
* pointerup
*/
private onPointerUp = (event: PointerEvent): void => {
if (!this.enabled) return
this.dragStartMouse.set(NaN, NaN)
this.isPointerDown = false
// console.log('enable controls')
this.viewport.controls.enabled = true
if (this.isDragging) {
const startPos = this.dragStartMouse
const targetPos = new THREE.Vector2(CurrentMouseInfo.x, CurrentMouseInfo.z)
if (startPos && targetPos) {
this.dragComplete(startPos, targetPos)
}
}
}
/**
* pointerleave
*/
private onPointerLeave = (_event: PointerEvent): void => {
if (!this.enabled) return
this.cleanupDrag()
}
}

28
src/core/engine/Viewport.ts

@ -22,6 +22,7 @@ import StateManager from '@/core/manager/StateManager.ts'
import EventBus from '@/runtime/EventBus.ts'
import Constract from '@/core/Constract.ts'
import type { IMeta } from '@/core/base/IMeta.ts'
import DragControl2 from '@/core/controls/EsDragControl2.ts'
/**
*
@ -34,15 +35,17 @@ export default class Viewport {
statsControls: Stats
controls: OrbitControls
raycaster: THREE.Raycaster
dragControl: any // EsDragControls
// dragControl: any // EsDragControls
animationFrameId: any = null
scene: SceneHelp
selectInspect = new SelectInspect()
mouseMoveInspect = new MouseMoveInspect()
dragControl = new DragControl2()
tools: IControls[] = [
markRaw(this.selectInspect),
markRaw(this.mouseMoveInspect)
markRaw(this.mouseMoveInspect),
markRaw(this.dragControl)
]
// 状态管理器
@ -155,18 +158,9 @@ export default class Viewport {
this.renderer = renderer
// 创建正交摄像机
// this.initMode2DCamera()
this.watchList.push(watch(() => this.state.view3DMode, (newVal) => {
if (newVal === Constract.Mode3D) {
this.initMode3DCamera()
} else {
this.initMode2DCamera()
}
}, { immediate: true }))
// 注册拖拽组件
this.dragControl = new EsDragControls(this)
// this.dragControl = new EsDragControls(this)
// 性能监控
const statsControls = new Stats()
@ -202,6 +196,16 @@ export default class Viewport {
tool.init(this)
}
// 创建正交摄像机
// this.initMode2DCamera()
this.watchList.push(watch(() => this.state.view3DMode, (newVal) => {
if (newVal === Constract.Mode3D) {
this.initMode3DCamera()
} else {
this.initMode2DCamera()
}
}, { immediate: true }))
// 触发所有物品类型的 afterAddViewport 方法
_.forEach(getAllItemTypes(), (itemType: ItemTypeDefineOption) => {
itemType.clazz.afterAddViewport(this)

2
src/model/itemType/ItemType.ts

@ -60,7 +60,7 @@ export default abstract class ItemType {
* viewport
*/
afterAddViewport(viewport: Viewport): void {
viewport.dragControl.setDragObjects(this.pointArray, 'push')
//viewport.dragControl.setDragObjects(this.pointArray, 'push')
const toolbox = this.createToolbox(viewport)
viewport.toolbox[this.name] = toolbox
}

2
src/model/itemType/Toolbox.ts

@ -290,7 +290,7 @@ export default abstract class Toolbox {
this.addToScene(marker)
// 把点加入拖拽控制器
this.viewport.dragControl.setDragObjects([marker], 'push')
//this.viewport.dragControl.setDragObjects([marker], 'push')
if (this.startPoint) {
this.afterAddPoint(this.startPoint, marker)

29
src/modules/gstore/GstoreRenderer.ts

@ -41,7 +41,6 @@ export default class GstoreRenderer extends BaseRenderer {
)
}
createLineBasic(start: ItemJson, end: ItemJson, type: LinkType): THREE.Object3D[] {
throw new Error('not allow store line.')
}
@ -50,6 +49,10 @@ export default class GstoreRenderer extends BaseRenderer {
throw new Error('not allow store line.')
}
createPointBasic(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] {
throw new Error('not allow createPointBasic.')
}
createPoint(item: ItemJson, option?: RendererCudOption): THREE.Object3D[] {
// 创建平面几何体
if (!item.dt.storeWidth || !item.dt.storeDepth) {
@ -59,7 +62,7 @@ export default class GstoreRenderer extends BaseRenderer {
group.name = GstoreRenderer.POINT_NAME
// 绘制背景矩形框
const planeGeometry = new THREE.PlaneGeometry(item.dt.storeWidth, item.dt.storeDepth);
const planeGeometry = new THREE.PlaneGeometry(item.dt.storeWidth, item.dt.storeDepth)
planeGeometry.rotateX(Math.PI / 2)
const planeMaterial = new THREE.MeshBasicMaterial({
color: '#dee8ee',
@ -67,8 +70,8 @@ export default class GstoreRenderer extends BaseRenderer {
opacity: 0.5, // 50%透明度
depthWrite: false, // 防止深度冲突
side: THREE.DoubleSide // 双面渲染:ml-citation{ref="5,8" data="citationList"}
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)
group.add(planeMesh)
// 绘制边框
@ -76,30 +79,32 @@ export default class GstoreRenderer extends BaseRenderer {
const lineYLen = item.dt.storeDepth - this.defaultLineWidth
const lineGeometry = new LineGeometry().setPositions([
-(lineXLen/2),0,-(lineYLen/2),
lineXLen/2,0,-(lineYLen/2),
lineXLen/2,0,lineYLen/2,
-(lineXLen/2),0,lineYLen/2,
-(lineXLen/2),0,-(lineYLen/2)
]);
-(lineXLen / 2), 0, -(lineYLen / 2),
lineXLen / 2, 0, -(lineYLen / 2),
lineXLen / 2, 0, lineYLen / 2,
-(lineXLen / 2), 0, lineYLen / 2,
-(lineXLen / 2), 0, -(lineYLen / 2)
])
const lineMaterial = new LineMaterial({
color: '#038217',
linewidth: this.defaultLineWidth,
worldUnits: true,
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
side: THREE.DoubleSide
});
})
//
const line = new Line2(lineGeometry, lineMaterial);
const line = new Line2(lineGeometry, lineMaterial)
group.add(line as THREE.Object3D)
// 设置位置
group.position.set(item.tf[0][0], item.tf[0][1], item.tf[0][2])
const points = [group]
this.fillObjectUserDataFromItem(item, ...points)
this.afterCreateOrUpdatePoint(item, option, points)
this.tempViewport.entityManager.appendObject(item.id, points)
this.appendToScene(...points)
return points
}

2
src/modules/measure/MeasureRenderer.ts

@ -110,7 +110,7 @@ export default class MeasureRenderer extends BaseRenderer {
}
const dragObjects = objects.filter(obj => !!obj.userData.draggable)
this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
//this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
this.group.add(...objects)
}

2
src/modules/way/WayRenderer.ts

@ -177,7 +177,7 @@ export default class WayRenderer extends BaseRenderer {
appendToScene(...objects: THREE.Object3D[]) {
const dragObjects = objects.filter(obj => !!obj.userData.draggable)
this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
//this.tempViewport.dragControl.setDragObjects(dragObjects, 'push')
// this.tempViewport.dragControl.setDragObjects(objects, 'remove')
this.tempViewport?.scene.add(...objects)

Loading…
Cancel
Save