Browse Source

MouseMoveInspect

master
修宁 7 months ago
parent
commit
e83ed20224
  1. 76
      src/designer/Viewport.ts
  2. 4
      src/designer/model2DEditor/Model2DEditor.vue
  3. 5
      src/designer/model2DEditor/tools/ITools.ts
  4. 48
      src/designer/model2DEditor/tools/MouseMoveInspect.ts
  5. 9
      src/designer/model3DView/Model3DView.vue

76
src/designer/Viewport.ts

@ -1,11 +1,13 @@
import _ from 'lodash' import _ from 'lodash'
import * as THREE from 'three' import * as THREE from 'three'
import { AxesHelper, GridHelper, OrthographicCamera, Scene, WebGLRenderer } from 'three' import { AxesHelper, GridHelper, OrthographicCamera, Raycaster, Scene, WebGLRenderer } from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import Stats from 'three/examples/jsm/libs/stats.module' import Stats from 'three/examples/jsm/libs/stats.module'
import type WorldModel from '@/designer/WorldModel.ts' import type WorldModel from '@/designer/WorldModel.ts'
import $ from 'jquery' import $ from 'jquery'
import { watch } from 'vue' import { reactive, watch } from 'vue'
import MouseMoveInspect from '@/designer/model2DEditor/tools/MouseMoveInspect.ts'
import type { ITools } from '@/designer/model2DEditor/tools/ITools.ts'
/** /**
* *
@ -21,8 +23,13 @@ export default class Viewport {
statsControls: Stats statsControls: Stats
controls: OrbitControls controls: OrbitControls
worldModel: WorldModel worldModel: WorldModel
raycaster: Raycaster
animationFrameId: any = null animationFrameId: any = null
tools: ITools[] = [
new MouseMoveInspect()
]
/** /**
* *
*/ */
@ -30,15 +37,24 @@ export default class Viewport {
unwatchList: (() => void)[] = [] unwatchList: (() => void)[] = []
state: ViewportState = { //@ts-ignore
currentFloor: null, state: ViewportState = reactive({
currentFloor: '',
isReady: false, isReady: false,
cursorMode: 'normal', cursorMode: 'normal',
camera: { camera: {
position: { x: 0, y: 0, z: 0 }, position: { x: 0, y: 0, z: 0 },
rotation: { x: 0, y: 0, z: 0 } rotation: { x: 0, y: 0, z: 0 }
},
mouse: {
leftPx: 0,
topPx: 0,
posX: 0,
posZ: 0,
x: 0,
y: 0
} }
} })
constructor(worldModel: WorldModel) { constructor(worldModel: WorldModel) {
this.worldModel = worldModel this.worldModel = worldModel
@ -143,6 +159,12 @@ export default class Viewport {
this.resizeObserver = new ResizeObserver(this.handleResize.bind(this)) this.resizeObserver = new ResizeObserver(this.handleResize.bind(this))
this.resizeObserver.observe(this.viewerDom) this.resizeObserver.observe(this.viewerDom)
this.raycaster = new Raycaster()
for (const tool of this.tools) {
tool.init(this)
}
this.state.isReady = true this.state.isReady = true
} }
@ -182,12 +204,12 @@ export default class Viewport {
controlsNew.screenSpacePanning = false // 定义平移时如何平移相机的位置 控制不上下移动 controlsNew.screenSpacePanning = false // 定义平移时如何平移相机的位置 控制不上下移动
controlsNew.listenToKeyEvents(viewerDom) // 监听键盘事件 controlsNew.listenToKeyEvents(viewerDom) // 监听键盘事件
controlsNew.keys = { LEFT: 'KeyA', UP: 'KeyW', RIGHT: 'KeyD', BOTTOM: 'KeyS' } controlsNew.keys = { LEFT: 'KeyA', UP: 'KeyW', RIGHT: 'KeyD', BOTTOM: 'KeyS' }
controlsNew.addEventListener('change', this.syncCameraState.bind(this))
controlsNew.panSpeed = 1 controlsNew.panSpeed = 1
controlsNew.keyPanSpeed = 20 // normal 7 controlsNew.keyPanSpeed = 20 // normal 7
controlsNew.minDistance = 0.1 controlsNew.minDistance = 0.1
controlsNew.maxDistance = 1000 controlsNew.maxDistance = 1000
this.controls = controlsNew this.controls = controlsNew
controlsNew.addEventListener('change', this.syncCameraState.bind(this))
this.camera.updateProjectionMatrix() this.camera.updateProjectionMatrix()
@ -279,7 +301,6 @@ export default class Viewport {
// 修改网格材质透明度 // 修改网格材质透明度
this.gridHelper.material.opacity = opacity this.gridHelper.material.opacity = opacity
this.gridHelper.visible = opacity > 0 this.gridHelper.visible = opacity > 0
console.log('opacity', opacity)
} }
destroy() { destroy() {
@ -297,6 +318,15 @@ export default class Viewport {
this.unwatchList = [] this.unwatchList = []
} }
if (this.tools) {
for (const tool of this.tools) {
if (tool.destory) {
tool.destory()
}
}
this.tools = []
}
if (this.resizeObserver) { if (this.resizeObserver) {
this.resizeObserver.unobserve(this.viewerDom) this.resizeObserver.unobserve(this.viewerDom)
this.resizeObserver.disconnect() this.resizeObserver.disconnect()
@ -316,6 +346,15 @@ export default class Viewport {
this.renderer.domElement = null this.renderer.domElement = null
} }
} }
/**
*
*/
getGridHelpAtPosition(param: { x: number; z: number }) {
const pickPosition = new THREE.Vector2(param.x, param.z)
this.raycaster.setFromCamera(pickPosition, this.camera)
return this.raycaster.intersectObject(this.gridHelper)
}
} }
export interface ViewportState { export interface ViewportState {
@ -341,4 +380,27 @@ export interface ViewportState {
position: { x: number, y: number, z: number }, position: { x: number, y: number, z: number },
rotation: { x: number, y: number, z: number } rotation: { x: number, y: number, z: number }
} }
/**
* ()
*/
mouse: {
/*
* DOM
*/
leftPx: number,
topPx: number,
/**
* THREE
*/
posX: number,
posZ: number,
/**
*
*/
x: number,
z: number
}
} }

4
src/designer/model2DEditor/Model2DEditor.vue

@ -9,7 +9,7 @@
:props="{emitPath:false}" /> :props="{emitPath:false}" />
</div> </div>
<div class="section-content"> <div class="section-content">
<div v-if="currentFloor" :key="currentFloor" :title="'当前楼层:'+currentFloor" <div v-if="currentFloor" :key="currentFloor"
class="canvas-container" ref="canvasContainer" tabindex="1" /> class="canvas-container" ref="canvasContainer" tabindex="1" />
</div> </div>
<div class="section-bottom-toolbar section-toolbar" v-if="isReady"> <div class="section-bottom-toolbar section-toolbar" v-if="isReady">
@ -56,7 +56,7 @@
</div> </div>
<span class="section-toolbar-line"></span> <span class="section-toolbar-line"></span>
<div class="infor"> <div class="infor">
X=14.091,Y=12.397 {{ state.mouse.x.toFixed(2) }},{{ state.mouse.z.toFixed(2) }}
</div> </div>
</div> </div>
</div> </div>

5
src/designer/model2DEditor/tools/ITools.ts

@ -0,0 +1,5 @@
export interface ITools {
init(viewport: any): void
destory(): void
}

48
src/designer/model2DEditor/tools/MouseMoveInspect.ts

@ -1,16 +1,56 @@
import Editor from '@/designer/Editor.js'
import type Viewport from '@/designer/Viewport.ts' import type Viewport from '@/designer/Viewport.ts'
import type { ITools } from '@/designer/model2DEditor/tools/ITools.ts'
/** /**
* designer.mousePos * designer.mousePos
*/ */
export default class MouseMoveInspect { export default class MouseMoveInspect implements ITools {
viewport: Viewport viewport: Viewport
constructor(viewport: Viewport) { constructor() {
}
init(viewport: Viewport) {
this.viewport = viewport this.viewport = viewport
const viewerDom = this.viewport.viewerDom
viewerDom.addEventListener('mousemove', this.mouseMove.bind(this))
}
destory() {
const viewerDom = this.viewport.viewerDom
viewerDom.removeEventListener('mousemove', this.mouseMove.bind(this))
}
mouseMove = _.throttle(function(this: MouseMoveInspect, event: MouseEvent) {
const viewer = this.viewport.viewerDom
// 获取鼠标在three.js 中的归一化坐标 取值范围是 (-1 to +1)
const rect = viewer.getBoundingClientRect()
this.viewport.state.mouse.leftPx = event.clientX - rect.left
this.viewport.state.mouse.topPx = event.clientY - rect.top
this.viewport.state.mouse.posX = ((event.clientX - rect.left) / rect.width) * 2 - 1
this.viewport.state.mouse.posZ = ((event.clientY - rect.top) / rect.height) * -2 + 1
const intersects = this.viewport.getGridHelpAtPosition({
x: this.viewport.state.mouse.posX,
z: this.viewport.state.mouse.posZ
})
if (!intersects || intersects.length < 2) {
this.viewport.state.mouse.x = NaN
this.viewport.state.mouse.z = NaN
return
} }
mouseMove(event) { if (!_.every(intersects, (intersect) => intersect.object.type === 'GridHelper')) {
this.viewport.state.mouse.x = NaN
this.viewport.state.mouse.z = NaN
return
} }
this.viewport.state.mouse.x = Math.floor(intersects[0].point.x * 10) / 10
this.viewport.state.mouse.z = Math.floor(intersects[0].point.z * 10) / 10
}, 1)
} }

9
src/designer/model3DView/Model3DView.vue

@ -91,7 +91,7 @@ const transformEditCtl = ref(null)
// Three.js // Three.js
let scene, camera, renderer, controls let scene, camera, renderer, controls
let statsControls, axesHelper, gridHelper let statsControls, axesHelper, gridHelper, animationFrameId
let gui, tcontrols, modelGroup, resizeObserver let gui, tcontrols, modelGroup, resizeObserver
const restate = reactive({ const restate = reactive({
@ -130,6 +130,11 @@ onMounted(() => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (animationFrameId !== null) {
cancelAnimationFrame(animationFrameId)
animationFrameId = null
}
cleanupThree() cleanupThree()
const viewerDom = canvasContainer.value const viewerDom = canvasContainer.value
@ -245,7 +250,7 @@ function initThree() {
// //
function animate() { function animate() {
requestAnimationFrame(animate) animationFrameId = requestAnimationFrame(animate)
renderView() renderView()
} }

Loading…
Cancel
Save