|
|
@@ -0,0 +1,690 @@
|
|
|
+<template src="./mapComponent.html"></template>
|
|
|
+<script>
|
|
|
+ // import AMapLoader from "@amap/amap-jsapi-loader";
|
|
|
+ import * as THREE from 'three';
|
|
|
+ import Stats from 'three/addons/libs/stats.module.js';
|
|
|
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
|
+ import { DragControls } from 'three/addons/controls/DragControls.js';
|
|
|
+ import leftOperateComp from "@/components/leftOperateComp/leftOperateComp";
|
|
|
+ export default {
|
|
|
+ name: "mapComponent",
|
|
|
+ props: {},
|
|
|
+ components:{
|
|
|
+ leftOperateComp
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ area: null,
|
|
|
+ selectModuleItem: null,
|
|
|
+ showMap: false,
|
|
|
+ is3D: true,
|
|
|
+ isOpen: false, //是否打开项目展示
|
|
|
+ scene: null,
|
|
|
+ camera: null,
|
|
|
+ canvas: null,
|
|
|
+ renderer: null,
|
|
|
+ stats:null,
|
|
|
+ starWorldPosition:null,
|
|
|
+ drawAreaObject:null,
|
|
|
+ XLine:null,
|
|
|
+ YLine:null,
|
|
|
+ areaList:[],//用户绘制的空间存放的数据对象
|
|
|
+ pageStatus:1, //当前页面状态 1 显示态 2 编辑态
|
|
|
+ cursorObj:null, //鼠标当前划过的对象
|
|
|
+ cursorMeshColor:null, //记录下划过对象的元素颜色
|
|
|
+ moveObj:null, //移动对象
|
|
|
+ moveStarPosition:null, //移动对象的初始位置-用于计算移动距离
|
|
|
+ adsorbDis:0.3, //移动对象时的吸附距离
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {},
|
|
|
+ watch: {
|
|
|
+ // areaData: {
|
|
|
+ // handler(newVal) {
|
|
|
+ // if(newVal){
|
|
|
+ // this.loadMap();
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ // immediate: true
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ var isDrawing = false;
|
|
|
+ // this.loadMap();
|
|
|
+ // window.$bus.$off('loginSuccess',this.loadMap);
|
|
|
+ // window.$bus.$on('loginSuccess', this.loadMap);
|
|
|
+ // window.$bus.$off('resetMap');
|
|
|
+ // window.$bus.$on('resetMap', (data) => {
|
|
|
+ // this.isOpen = data;
|
|
|
+ // this.resetMapCenter();
|
|
|
+ // })
|
|
|
+ var that = this;
|
|
|
+ const container = this.$refs.webgl;
|
|
|
+ this.stats = new Stats();
|
|
|
+ container.appendChild(this.stats.dom);
|
|
|
+
|
|
|
+ this.scene = new THREE.Scene();//场景对象
|
|
|
+ this.scene.background = new THREE.Color("#fff");//设置场景的背景色
|
|
|
+ // this.scene.environment = new THREE.Color("#ccc");
|
|
|
+ //创建透视相机
|
|
|
+ this.camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 10000);
|
|
|
+ this.camera.position.set(0, 0, 15);
|
|
|
+ this.scene.add(this.camera);//把相机添加到场景里面
|
|
|
+ // const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
|
|
|
+ // this.scene.add( ambientLight );
|
|
|
+ const canvas3d = this.$refs.glcanvas;
|
|
|
+ //创建渲染器
|
|
|
+ this.renderer = new THREE.WebGLRenderer({
|
|
|
+ canvas:canvas3d,
|
|
|
+ antialias: false,
|
|
|
+ preserveDrawingBuffer: true,
|
|
|
+ });
|
|
|
+ this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
+ container.appendChild(this.renderer.domElement);
|
|
|
+
|
|
|
+ //极坐标辅助
|
|
|
+ // const axesHelper = new THREE.AxesHelper( 50 );
|
|
|
+ // this.scene.add( axesHelper );
|
|
|
+ //网格辅助
|
|
|
+ const gridHelper = new THREE.GridHelper(50, 50, 0x808080, 0x808080);
|
|
|
+ gridHelper.position.y = 0;
|
|
|
+ gridHelper.position.x = 0;
|
|
|
+ gridHelper.rotation.x = Math.PI / 2;//翻转
|
|
|
+ gridHelper.name = "辅助网格"
|
|
|
+ this.scene.add(gridHelper);
|
|
|
+
|
|
|
+ // 4.创建一个长、宽、高均为5个单位的立方体
|
|
|
+ // const geometry = new THREE.BoxGeometry(5, 5, 5);
|
|
|
+ // 创建一个长、宽、的矩形;three.js 默认单位是米
|
|
|
+ const geometry = new THREE.PlaneGeometry(50, 50);
|
|
|
+
|
|
|
+ // 5.创建Lambert网格材质
|
|
|
+ const materialBasic = new THREE.MeshBasicMaterial({
|
|
|
+ color: 'transparent', // 绿色
|
|
|
+ transparent: true, // 设置材质为透明
|
|
|
+ opacity: 0.5 // 设置透明度
|
|
|
+ });
|
|
|
+ // 6.创建一个网格模型对象
|
|
|
+ const mesh = new THREE.Mesh(geometry, materialBasic); //网络模型对象Mesh
|
|
|
+ mesh.position.set(0, 0, 0);
|
|
|
+ mesh.name="bgPan";//背景板-用于计算鼠标点击以及滑动时的位置-精确位置
|
|
|
+ // 把网格模型添加到三维场景
|
|
|
+ this.scene.add(mesh);
|
|
|
+
|
|
|
+ // 设置相机看向物体的方向(默认指向三维坐标系的原点)
|
|
|
+ // this.camera.lookAt(0, 0, 0);
|
|
|
+ // 修改几何体位置
|
|
|
+ // const controls = new OrbitControls( this.camera, this.renderer.domElement );
|
|
|
+ // controls.target.set( 0, 0.5, 0 );
|
|
|
+ // controls.update();
|
|
|
+ // controls.enablePan = false;
|
|
|
+ // controls.enableDamping = true;
|
|
|
+
|
|
|
+ // function render(){
|
|
|
+ // this.renderer.render(this.scene, this.camera);//单次渲染
|
|
|
+ // requestAnimationFrame(render)
|
|
|
+ // }
|
|
|
+ const raycaster = new THREE.Raycaster();
|
|
|
+ this.render(); //开启渲染
|
|
|
+ this.renderer.domElement.addEventListener('mousemove', onMouseMove, false);
|
|
|
+ this.renderer.domElement.addEventListener('mouseup', mouseup, false);//释放鼠标
|
|
|
+ this.renderer.domElement.addEventListener('mousedown', mousedown, false);//按下鼠标
|
|
|
+ this.renderer.domElement.addEventListener('contentmenu', contentmenu, false);//右键事件
|
|
|
+ const labelContainerElem = document.querySelector('#labels');
|
|
|
+ window.onresize = ()=> {
|
|
|
+ this.camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
+ this.camera.updateProjectionMatrix();
|
|
|
+ this.renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
+ };
|
|
|
+ //把鼠标的点击坐标-屏幕坐标转换为three.js体系里面的世界坐标
|
|
|
+ function getWorldPoint (event) {
|
|
|
+ var mouse = new THREE.Vector2();
|
|
|
+ mouse.x = (event.clientX / window.innerWidth) * (2/window.devicePixelRatio) - 1;
|
|
|
+ mouse.y = -(event.clientY / window.innerHeight) * (2/window.devicePixelRatio) + 1;
|
|
|
+ raycaster.setFromCamera(mouse, that.camera);
|
|
|
+ var intersects = raycaster.intersectObjects(that.scene.children);
|
|
|
+ // var intersects = raycaster.intersectObjects(that.camera);
|
|
|
+ if (intersects.length > 0) {
|
|
|
+ let meshMap = intersects.find(it => {
|
|
|
+ return it.object.name=="bgPan" && it.point
|
|
|
+ });
|
|
|
+ var worldPosition = {};
|
|
|
+ if(meshMap && meshMap.point){
|
|
|
+ worldPosition = meshMap.point;
|
|
|
+ }
|
|
|
+ return worldPosition;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取当前鼠标悬浮到的哪个空间上-也即选取对应的空间
|
|
|
+ function getSelectArea (event) {
|
|
|
+ var mouse = new THREE.Vector2();
|
|
|
+ mouse.x = (event.clientX / window.innerWidth) * (2/window.devicePixelRatio) - 1;
|
|
|
+ mouse.y = -(event.clientY / window.innerHeight) * (2/window.devicePixelRatio) + 1;
|
|
|
+ raycaster.setFromCamera(mouse, that.camera);
|
|
|
+ var intersects = raycaster.intersectObjects(that.areaList);
|
|
|
+ // var intersects = raycaster.intersectObjects(that.camera);
|
|
|
+ if (intersects.length > 0) {
|
|
|
+ let selectArea = intersects[0].object;
|
|
|
+ return selectArea;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //鼠标右键事件
|
|
|
+ function contentmenu (event) {
|
|
|
+ console.warn("***contentmenu***")
|
|
|
+ that.starWorldPosition = null;//清空初始点击位置
|
|
|
+ }
|
|
|
+ //释放鼠标
|
|
|
+ function mouseup(event) {
|
|
|
+ if(that.pageStatus==1){//页面处在显示态
|
|
|
+ if(that.moveObj){//存在移动对象-也就是用户点击过屏幕,系统拾取了移动对象
|
|
|
+ that.moveObj.material.opacity = 1;
|
|
|
+ that.moveObj = null;//清空移动对象
|
|
|
+ }else{
|
|
|
+ // cursorMove(event);//鼠标划过处理
|
|
|
+ }
|
|
|
+ }else if(that.pageStatus==2){//页面处在编辑态-即绘制状态
|
|
|
+ isDrawing = false;
|
|
|
+ that.starWorldPosition = null;//清空初始点击位置
|
|
|
+ that.areaList.push(that.drawAreaObject);//把用户绘制的空间添加到空间列表中
|
|
|
+ that.drawAreaObject = null;//清空
|
|
|
+ console.warn("***mouseup-that.areaList***",that.areaList)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //按下鼠标
|
|
|
+ function mousedown(event) {
|
|
|
+ console.warn("***mousedown***")
|
|
|
+ if(!event){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(that.pageStatus==1){//页面处在显示态
|
|
|
+ if(that.cursorObj){//如果存在滑动对象-则需要拾取它-因为下一步要移动
|
|
|
+ that.moveObj = that.cursorObj;//声明并且赋值移动对象
|
|
|
+ that.moveStarPosition = getWorldPoint(event);//记录下移动对象初始点击的位置
|
|
|
+ }else{//点击时没有滑动对象,则需要把上一次的移动对象清空
|
|
|
+ that.moveObj = null;
|
|
|
+ }
|
|
|
+ }else if(that.pageStatus==2){//页面处在编辑态-即绘制状态
|
|
|
+ isDrawing = true;
|
|
|
+ let posi = getWorldPoint(event);
|
|
|
+ that.starWorldPosition = posi;//记录下点击的位置
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //鼠标移动中
|
|
|
+ function onMouseMove(event) {
|
|
|
+ // event.preventDefault();
|
|
|
+ if(that.pageStatus==1){//页面处在显示态
|
|
|
+ if(that.moveObj){//存在移动对象-也就是用户点击过屏幕,系统拾取了移动对象
|
|
|
+ moveObj(that.moveObj,event)
|
|
|
+ }else{
|
|
|
+ cursorMove(event);//鼠标划过处理
|
|
|
+ }
|
|
|
+ }else if(that.pageStatus==2){//页面处在编辑态
|
|
|
+ if (!isDrawing) return;
|
|
|
+ let _position = getWorldPoint(event);
|
|
|
+ if(!_position || !_position.x){//没有获取到坐标,可能发生了越界
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(!that.drawAreaObject){//此时需要创建drawAreaObject
|
|
|
+ // // 创建一个长、宽、的矩形;three.js 默认单位是米
|
|
|
+ let width = 1;
|
|
|
+ let height = 1;
|
|
|
+ const geometry = new THREE.PlaneGeometry(width, height);
|
|
|
+
|
|
|
+ // 5.创建Lambert网格材质
|
|
|
+ const materialBasic = new THREE.MeshBasicMaterial({
|
|
|
+ color: 0x00ff00, // 绿色
|
|
|
+ });
|
|
|
+ // // 6.创建一个网格模型对象
|
|
|
+ const mesh = new THREE.Mesh(geometry, materialBasic); //网络模型对象Mesh
|
|
|
+ mesh.position.set(that.starWorldPosition.x + width/2, that.starWorldPosition.y - height/2, 0);
|
|
|
+
|
|
|
+ that.drawAreaObject = mesh;
|
|
|
+ that.scene.add(that.drawAreaObject);
|
|
|
+ that.drawAreaObject.starWorldPosition = that.starWorldPosition;
|
|
|
+ }
|
|
|
+
|
|
|
+ var width = _position.x - that.starWorldPosition.x;
|
|
|
+ var height = -(_position.y - that.starWorldPosition.y);//注意Y方向上的正方向是向上的
|
|
|
+
|
|
|
+ that.drawAreaObject.scale.set(width, height, 1);
|
|
|
+ that.drawAreaObject.position.set(that.starWorldPosition.x + width / 2, that.starWorldPosition.y - height / 2, 0);
|
|
|
+ drawXLine(_position); //绘制X轴提示线
|
|
|
+ drawYLine(_position); //绘制Y轴提示线
|
|
|
+ drawArea(_position) //绘制面积提示语
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //绘制X轴提示线-2D position 鼠标对应的点
|
|
|
+ function drawXLine (position) {
|
|
|
+ let startPosition = that.starWorldPosition;
|
|
|
+ let endPosition = position;
|
|
|
+ //数据过滤-确保数据是正确的
|
|
|
+ if(!startPosition || !endPosition || !startPosition.x || !endPosition.x){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(startPosition.x == endPosition.x){//线段的开始点和结束点不能相同
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ let cha = 0.1;//偏移量
|
|
|
+ if(endPosition.y > startPosition.y){
|
|
|
+ cha = -0.1
|
|
|
+ }
|
|
|
+ let XLine = that.drawAreaObject.XLine;
|
|
|
+ if(!XLine){//如果当前绘制的空间没有X轴提示线
|
|
|
+ // 创建线的几何体
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+ // 初始线的顶点位置
|
|
|
+ var positions = new Float32Array(6);
|
|
|
+ positions[0] = startPosition.x; // x1
|
|
|
+ positions[1] = startPosition.y + cha; // y1
|
|
|
+ positions[2] = 0; // z1
|
|
|
+ positions[3] = endPosition.x; // x2
|
|
|
+ positions[4] = startPosition.y + cha; // y2
|
|
|
+ positions[5] = 0; // z2
|
|
|
+ // 设置线的属性
|
|
|
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
|
+ const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
|
|
|
+ const line = new THREE.Line( geometry, material );
|
|
|
+ that.drawAreaObject.XLine = line;//保存X轴提示线
|
|
|
+ that.scene.add(line);
|
|
|
+ }else{
|
|
|
+ XLine.geometry.attributes.position.array[1] = startPosition.y + cha; // y1
|
|
|
+ XLine.geometry.attributes.position.array[3] = endPosition.x;
|
|
|
+ XLine.geometry.attributes.position.array[4] = startPosition.y + cha;
|
|
|
+ XLine.geometry.attributes.position.needsUpdate = true;
|
|
|
+ }
|
|
|
+ //超过1个单位的距离,才显示
|
|
|
+ if( Math.abs(endPosition.x - startPosition.x)/2 > 1 ){
|
|
|
+ if(XLine && XLine.elem){
|
|
|
+ XLine.elem.style.display = 'block';
|
|
|
+ }
|
|
|
+ let content = "";
|
|
|
+ let tempV = new THREE.Vector3();
|
|
|
+ tempV.x = (endPosition.x + startPosition.x)/2;
|
|
|
+ tempV.y = startPosition.y + cha*4;
|
|
|
+ tempV.z = 0;
|
|
|
+ content = Math.abs(endPosition.x - startPosition.x).toFixed(2) + 'm';
|
|
|
+ makeTips(XLine,tempV,content)
|
|
|
+ }else{
|
|
|
+ if(XLine && XLine.elem){
|
|
|
+ XLine.elem.style.display = 'none';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //绘制Y轴提示线-2D position 鼠标对应的点
|
|
|
+ function drawYLine (position) {
|
|
|
+ let startPosition = that.starWorldPosition;
|
|
|
+ let endPosition = position;
|
|
|
+ //数据过滤-确保数据是正确的
|
|
|
+ if(!startPosition || !endPosition || !startPosition.y || !endPosition.y){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(startPosition.y == endPosition.y){//线段的开始点和结束点不能相同
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ let cha = 0.1;
|
|
|
+ if(endPosition.x > startPosition.x){
|
|
|
+ cha = -0.1
|
|
|
+ }
|
|
|
+ let YLine = that.drawAreaObject.YLine;
|
|
|
+ if(!YLine){//如果当前绘制的空间没有X轴提示线
|
|
|
+ // 创建线的几何体
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+ // 初始线的顶点位置
|
|
|
+ var positions = new Float32Array(6);
|
|
|
+ positions[0] = startPosition.x + cha; // x1
|
|
|
+ positions[1] = startPosition.y; // y1
|
|
|
+ positions[2] = 0; // z1
|
|
|
+ positions[3] = endPosition.x + cha; // x2
|
|
|
+ positions[4] = startPosition.y; // y2
|
|
|
+ positions[5] = 0; // z2
|
|
|
+ // 设置线的属性
|
|
|
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
|
+ const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
|
|
|
+ const line = new THREE.Line( geometry, material );
|
|
|
+
|
|
|
+ that.drawAreaObject.YLine = line;//保存X轴提示线
|
|
|
+ that.scene.add(line);
|
|
|
+ }else{
|
|
|
+ YLine.geometry.attributes.position.array[0] = startPosition.x + cha; // y1
|
|
|
+ YLine.geometry.attributes.position.array[3] = startPosition.x + cha;
|
|
|
+ YLine.geometry.attributes.position.array[4] = endPosition.y;
|
|
|
+ YLine.geometry.attributes.position.needsUpdate = true;
|
|
|
+ }
|
|
|
+ //超过1个单位的距离,才显示
|
|
|
+ if(Math.abs(endPosition.y - startPosition.y)/2 > 1 ){
|
|
|
+ if(YLine.elem){
|
|
|
+ YLine.elem.style.display = 'block';
|
|
|
+ }
|
|
|
+ let content = "";
|
|
|
+ let tempV = new THREE.Vector3();
|
|
|
+ tempV.x = startPosition.x + cha;
|
|
|
+ tempV.y = (endPosition.y + startPosition.y)/2;
|
|
|
+ tempV.z = 0;
|
|
|
+ content = Math.abs(endPosition.y - startPosition.y).toFixed(2) + 'm';
|
|
|
+ makeTips(YLine,tempV,content)
|
|
|
+ }else{
|
|
|
+ if(YLine && YLine.elem){
|
|
|
+ YLine.elem.style.display = 'none';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //绘制区域面积-2D position 鼠标对应的点
|
|
|
+ function drawArea (position) {
|
|
|
+ let startPosition = that.starWorldPosition;
|
|
|
+ let endPosition = position;
|
|
|
+ let obj = that.drawAreaObject;//当前绘制的空间对象
|
|
|
+ //数据过滤-确保数据是正确的
|
|
|
+ if(!startPosition || !endPosition || !startPosition.y || !endPosition.y
|
|
|
+ || !startPosition.x || !endPosition.x){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(startPosition.y == endPosition.y || startPosition.x == endPosition.x){//线段的开始点和结束点不能相同
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ if(Math.abs(endPosition.x - startPosition.x)/2 > 1 ){
|
|
|
+ let content = "";
|
|
|
+ let tempV = new THREE.Vector3();
|
|
|
+ tempV.x = (startPosition.x + endPosition.x)/2;
|
|
|
+ tempV.y = (startPosition.y + endPosition.y)/2;
|
|
|
+ tempV.z = 0;
|
|
|
+ content = (Math.abs(endPosition.y - startPosition.y)*Math.abs(endPosition.x - startPosition.x)).toFixed(2) + '㎡';
|
|
|
+ // console.log('makeTips-area', JSON.parse(JSON.stringify(tempV)),JSON.parse(JSON.stringify(endPosition)),JSON.parse(JSON.stringify(startPosition)),);
|
|
|
+ makeTips(obj,tempV,content)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //绘制和更新提示线上的距离值-单位米 point 是世界坐标系上的点位
|
|
|
+ function makeTips(line, point, content=null) {
|
|
|
+ if(!line){//如果没有提示线,则不处理
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(!line.elem){//提示线上不存在距离值div,则创建一个
|
|
|
+ let elem = document.createElement('div');
|
|
|
+ line.elem = elem;//向父级对象上添加div对象-方便父级对象找到这个div,从而操作
|
|
|
+ labelContainerElem.appendChild(line.elem);
|
|
|
+ }
|
|
|
+ const tempV = new THREE.Vector3();
|
|
|
+ tempV.x = point.x;
|
|
|
+ tempV.y = point.y;
|
|
|
+ tempV.z = point.z;
|
|
|
+ line.lableX = point.x;//记录下线上提示的位置
|
|
|
+ line.lableY = point.y;
|
|
|
+ // 获取标准化屏幕坐标,x和y都会在-1和1区间
|
|
|
+ // x = -1 表示在最左侧
|
|
|
+ // y = -1 表示在最底部
|
|
|
+ tempV.project(that.camera);
|
|
|
+ // window.innerWidth, window.innerHeight
|
|
|
+ // 将标准屏幕坐标转化为CSS坐标
|
|
|
+ const x = (tempV.x * .5 + .5) * window.innerWidth;
|
|
|
+ const y = (tempV.y * -.5 + .5) * window.innerHeight;
|
|
|
+ line.elem.textContent = content?content:line.elem.textContent;//提示的文字内容
|
|
|
+ // 将元素移动到此位置
|
|
|
+ line.elem.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
|
|
|
+ }
|
|
|
+ //鼠标划过处理
|
|
|
+ function cursorMove (event) {
|
|
|
+ let area = getSelectArea(event);//获取鼠标划过的空间
|
|
|
+ if(that.cursorObj){//当前存在鼠标划过的对象
|
|
|
+ if(!area){//从当前滑过对象上移开
|
|
|
+ that.cursorObj.material.color = that.cursorMeshColor;//恢复原来颜色
|
|
|
+ that.cursorObj = null;
|
|
|
+ that.cursorMeshColor = null;
|
|
|
+ document.body.style.cursor = 'default';//还原鼠标样式
|
|
|
+ }else{//当次还存在划过的对象
|
|
|
+ if(that.cursorObj.uuid == area.uuid){//一致,则不处理
|
|
|
+ return false;
|
|
|
+ }else{//不同
|
|
|
+ that.cursorObj.material.color = that.cursorMeshColor;//恢复原来颜色
|
|
|
+ that.cursorObj = area;//记录下当前鼠标划过的对象;
|
|
|
+ that.cursorMeshColor = area.material.color.clone();//复制当前模型材质的颜色,用与取消选中时还原
|
|
|
+ let color = new THREE.Color(0xff9f36); // 使用sRGB颜色值
|
|
|
+ color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值
|
|
|
+ area.material.color = color;//变更颜色
|
|
|
+ document.body.style.cursor = 'move';//修改鼠标样式
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{//不存在鼠标划过的对象
|
|
|
+ if(!area){
|
|
|
+ document.body.style.cursor = 'default';//修改鼠标样式
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ that.cursorMeshColor = area.material.color.clone();//复制当前模型材质的颜色,用与取消选中时还原
|
|
|
+ that.cursorObj = area;//记录下当前鼠标划过的对象;
|
|
|
+ let color = new THREE.Color(0xff9f36); // 使用sRGB颜色值
|
|
|
+ color.convertSRGBToLinear(); // 将颜色值转换为线性颜色值
|
|
|
+ area.material.color = color;//修改颜色
|
|
|
+ document.body.style.cursor = 'move';//修改鼠标样式
|
|
|
+ console.warn("****cursorObj***",that.cursorObj)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //空间对象移动
|
|
|
+ function moveObj (obj,event) {
|
|
|
+ if(!obj || !event){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let _position = getWorldPoint(event);
|
|
|
+ if(!_position || !_position.x){//没有获取到坐标,可能发生了越界
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let _x = _position.x - that.moveStarPosition.x;//相对上一次移动触发时的移动距离
|
|
|
+ let _y = _position.y - that.moveStarPosition.y;
|
|
|
+ if(_x==0 && _y==0){//没有变化
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(obj.adsorbLockX){//X轴吸附
|
|
|
+ if(_position.x <= obj.adsorDisMaxX && _position.x >= obj.adsorDisMinX ){//移动的距离没超过阈值-不实际移动
|
|
|
+ _x = 0;//锁定X轴,不移动
|
|
|
+ }else{
|
|
|
+ moveObjHandle(obj,-obj.adsorDisX,0);//补充移动,填补鼠标的偏移量
|
|
|
+ obj.adsorbLockX = false;//解锁,可以继续移动
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(obj.adsorbLockY){//Y轴吸附
|
|
|
+ if(_position.y <= obj.adsorDisMaxY && _position.y >= obj.adsorDisMinY ){//移动的距离没超过阈值-不实际移动
|
|
|
+ _y = 0;//锁定Y轴移动距离,不移动
|
|
|
+ }else{
|
|
|
+ moveObjHandle(obj,0,-obj.adsorDisY);//补充移动,填补鼠标的偏移量
|
|
|
+ obj.adsorbLockY = false;//解锁,可以继续移动
|
|
|
+ // console.warn("***moveObjHandle2***",_position.y,obj.adsorDisMaxY,obj.adsorDisMinY,obj.position.y)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // console.warn("***moveObjHandle0***",_x,_y,
|
|
|
+ // obj.adsorDisMaxX,obj.adsorDisMinX,
|
|
|
+ // obj.adsorDisMaxY,obj.adsorDisMinY,
|
|
|
+ // obj.adsorbLockX,obj.adsorbLockY,
|
|
|
+ // that.moveStarPosition.x,that.moveStarPosition.y)
|
|
|
+ //先移动
|
|
|
+ moveObjHandle(obj,_x,_y);
|
|
|
+ //没有锁定X轴时
|
|
|
+ if(!obj.adsorbLockX){//X轴吸附
|
|
|
+ that.moveStarPosition.x = _position.x;
|
|
|
+ }
|
|
|
+ //没有锁定Y轴时
|
|
|
+ if(!obj.adsorbLockY){//Y轴吸附
|
|
|
+ that.moveStarPosition.y = _position.y;
|
|
|
+ }
|
|
|
+ if(!obj.adsorbLockX || !obj.adsorbLockY){//当前移动对象没有锁定也即吸附
|
|
|
+ // that.moveStarPosition.x = _position.x;
|
|
|
+ // that.moveStarPosition.y = _position.y;
|
|
|
+ adsorbHandle(obj,_x,_y);//开始吸附处理
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //移动对象移动处理函数
|
|
|
+ function moveObjHandle(obj,_x=0,_y=0){
|
|
|
+ //先移动
|
|
|
+ if(obj.XLine){//如果移动对象存在X轴提示线
|
|
|
+ obj.XLine.translateX(_x);
|
|
|
+ obj.XLine.translateY(_y);
|
|
|
+ let tempV = new THREE.Vector3();//文字移动后的坐标位置-世界坐标系下
|
|
|
+ tempV.x = obj.XLine.lableX + _x;
|
|
|
+ tempV.y = obj.XLine.lableY + _y;
|
|
|
+ tempV.z = 0;
|
|
|
+ makeTips(obj.XLine,tempV)
|
|
|
+ }
|
|
|
+ if(obj.YLine){//如果移动对象存在Y轴提示线
|
|
|
+ obj.YLine.translateX(_x);
|
|
|
+ obj.YLine.translateY(_y);
|
|
|
+ let tempV = new THREE.Vector3();//文字移动后的坐标位置-世界坐标系下
|
|
|
+ tempV.x = obj.YLine.lableX + _x;
|
|
|
+ tempV.y = obj.YLine.lableY + _y;
|
|
|
+ tempV.z = 0;
|
|
|
+ makeTips(obj.YLine,tempV)
|
|
|
+ }
|
|
|
+ if(obj.elem){//如果移动对象存在面积提示lable
|
|
|
+ let tempV = new THREE.Vector3();//文字移动后的坐标位置-世界坐标系下
|
|
|
+ tempV.x = obj.lableX + _x;
|
|
|
+ tempV.y = obj.lableY + _y;
|
|
|
+ tempV.z = 0;
|
|
|
+ makeTips(obj,tempV)
|
|
|
+ }
|
|
|
+ obj.translateX(_x);
|
|
|
+ obj.translateY(_y);
|
|
|
+ }
|
|
|
+ //吸附处理函数
|
|
|
+ //移动结束后进行吸附经查
|
|
|
+ //吸附定义如下:如果移动对象进入其他空间边界线0.5m(adsorbDis)范围内,则触发吸附
|
|
|
+ //吸附过程中,只要移动对象没有离开吸附区域(由adsorbDis确定),则锁定移动目标;
|
|
|
+ //移动对象一旦离开吸附区域,则恢复至可移动状态,同时消除偏移量,确保鼠标位置正确
|
|
|
+ function adsorbHandle (obj,_x,_y) {
|
|
|
+ let direction = {
|
|
|
+ horizontal:'', //水平移动的方向
|
|
|
+ vertical:'', //垂直移动的方向
|
|
|
+ };
|
|
|
+ //计算移动方向-相对上一次的
|
|
|
+ if(_x>0){//向右移动
|
|
|
+ direction.horizontal = 'right';
|
|
|
+ }
|
|
|
+ else if(_x<0){//向左移动
|
|
|
+ direction.horizontal = 'left';
|
|
|
+ }
|
|
|
+ if(_y>0){//向上移动-检查上边界,下边界不做检查-当前逻辑
|
|
|
+ direction.vertical = 'up';
|
|
|
+ }
|
|
|
+ else if(_y<0){//向下移动-检查下边界,上边界不做检查-当前逻辑
|
|
|
+ direction.vertical = 'down';
|
|
|
+ }
|
|
|
+ let dis = adsorbCheck(obj,direction);//吸附检查
|
|
|
+ if(dis.x){
|
|
|
+ obj.adsorbLockX = true;//X轴吸附锁定
|
|
|
+ if(direction.horizontal == 'left'){
|
|
|
+ obj.adsorDisMaxX = that.moveStarPosition.x + (that.adsorbDis - dis.x);//吸附距离
|
|
|
+ obj.adsorDisMinX = that.moveStarPosition.x - (that.adsorbDis + dis.x);//吸附距离
|
|
|
+ }else if(direction.horizontal == 'right'){
|
|
|
+ obj.adsorDisMaxX = that.moveStarPosition.x + (that.adsorbDis + dis.x);//吸附距离
|
|
|
+ obj.adsorDisMinX = that.moveStarPosition.x - (that.adsorbDis - dis.x);//吸附距离
|
|
|
+ }
|
|
|
+ obj.adsorDisX = dis.x;//对象的偏移量-相对鼠标的
|
|
|
+ // obj.adsorDirec = direction.horizontal;//吸附方向
|
|
|
+ console.warn("***moveObj-checkX1***",dis,that.moveStarPosition.x,dis,direction,obj.adsorbLockX,obj.adsorbLockY)
|
|
|
+ }
|
|
|
+ if(dis.y){
|
|
|
+ obj.adsorbLockY = true;//Y轴吸附锁定
|
|
|
+ if(direction.vertical == 'down'){
|
|
|
+ obj.adsorDisMaxY = that.moveStarPosition.y + (that.adsorbDis - dis.y);//吸附距离
|
|
|
+ obj.adsorDisMinY = that.moveStarPosition.y - (that.adsorbDis + dis.y);//吸附距离
|
|
|
+ }else if(direction.vertical == 'up'){
|
|
|
+ obj.adsorDisMaxY = that.moveStarPosition.y + (that.adsorbDis + dis.y);//吸附距离
|
|
|
+ obj.adsorDisMinY = that.moveStarPosition.y - (that.adsorbDis - dis.y);//吸附距离
|
|
|
+ }
|
|
|
+ obj.adsorDisY = dis.y;//对象的偏移量-相对鼠标的
|
|
|
+ // obj.adsorDirec = direction.vertical;//吸附方向
|
|
|
+ console.warn("***moveObj-checkY2***",dis,that.moveStarPosition.y,dis,direction,obj.adsorbLockX,obj.adsorbLockY)
|
|
|
+ }
|
|
|
+ if(dis.x || dis.y){
|
|
|
+ moveObjHandle(obj,dis.x,dis.y);//补充移动
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //吸附检查-遍历所有绘制的空间;obj 当前操作的空间对象
|
|
|
+ //direction 移动的方向
|
|
|
+ //如果某一方向上没有变化,则不检测该方向,该方向返回为undefined
|
|
|
+ function adsorbCheck (obj,direction) {
|
|
|
+ let _areaList = that.areaList;
|
|
|
+ if(!_areaList || _areaList.length<2){//绘制的空间必须大于1个,检查才有意义
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ let _sourceX;
|
|
|
+ let _sourceY;
|
|
|
+ let _x,_y;//修正后的移动距离
|
|
|
+ if(direction.horizontal=='left'){//向左移动
|
|
|
+ _sourceX = obj.position.x - Math.abs(obj.scale.x/2);//获取右侧垂直线的X轴的值-世界坐标系
|
|
|
+ }else if(direction.horizontal=='right'){//向右移动
|
|
|
+ _sourceX = obj.position.x + Math.abs(obj.scale.x/2);//获取右侧垂直线的X轴的值-世界坐标系
|
|
|
+ }
|
|
|
+ if(direction.vertical=='up'){//向上移动
|
|
|
+ _sourceY = obj.position.y + Math.abs(obj.scale.y/2);//获取右侧垂直线的X轴的值-世界坐标系
|
|
|
+ }else if(direction.vertical=='down'){//向下移动
|
|
|
+ _sourceY = obj.position.y - Math.abs(obj.scale.y/2);//获取右侧垂直线的X轴的值-世界坐标系
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取其他空间的水平、垂直线
|
|
|
+ // _areaList.forEach((item,index)=>{
|
|
|
+ for (let item of _areaList) {
|
|
|
+ if(item!=obj){//其他空间对象
|
|
|
+ let leftX,rightX,topY,downY;
|
|
|
+ rightX = item.position.x + Math.abs(item.scale.x/2);//获取右侧垂直线的X轴的值-世界坐标系
|
|
|
+ leftX = item.position.x - Math.abs(item.scale.x/2);//获取左侧垂直线的X轴的值-世界坐标系
|
|
|
+ topY = item.position.y + Math.abs(item.scale.y/2);//获取up侧垂直线的X轴的值-世界坐标系
|
|
|
+ downY = item.position.y - Math.abs(item.scale.y/2);//获取左侧垂直线的X轴的值-世界坐标系
|
|
|
+ if(_sourceX != null && _x==null){//说明水平方向上有移动
|
|
|
+ if(Math.abs(_sourceX - rightX) < that.adsorbDis){//检查到距离差到达阈值
|
|
|
+ // console.warn("***adsorbDis-checkX1***",_sourceX,rightX,direction)
|
|
|
+ _x = rightX - _sourceX;
|
|
|
+ }else if(Math.abs(_sourceX - leftX) < that.adsorbDis){//检查到距离差到达阈值
|
|
|
+ // console.warn("***adsorbDis-checkX2***",_sourceX,leftX,direction)
|
|
|
+ _x = leftX - _sourceX;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(_sourceY != null && _y==null){//说明垂直方向上有移动
|
|
|
+ if(Math.abs(_sourceY - topY) < that.adsorbDis){//检查到距离差到达阈值
|
|
|
+ // console.warn("***adsorbDis-checkY1***",_sourceY,topY,direction)
|
|
|
+ _y = topY - _sourceY;
|
|
|
+ }else if(Math.abs(_sourceY - downY) < that.adsorbDis){//检查到距离差到达阈值
|
|
|
+ // console.warn("***adsorbDis-checkY2***",_sourceY,downY,direction)
|
|
|
+ _y = downY - _sourceY;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(_x != null && _y != null){//表示两个方向都要检查
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {x:_x,y:_y}
|
|
|
+ }
|
|
|
+ //绘制墙壁-2D
|
|
|
+ function drawWall () {
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ destroyed() {
|
|
|
+ window.map && typeof window.map.destroyed === "function" && window.map.destroyed();
|
|
|
+ window.map = null;
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ initData(area) {
|
|
|
+ this.area = area;
|
|
|
+ },
|
|
|
+ render() {
|
|
|
+ this.renderer.render(this.scene, this.camera); //单次渲染
|
|
|
+ this.stats.update();
|
|
|
+ requestAnimationFrame(this.render)
|
|
|
+ },
|
|
|
+ //操作监听
|
|
|
+ operateHandle(item){
|
|
|
+ if(!item || !item.id){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if(item.id==1){//空间新增
|
|
|
+ this.pageStatus = 2;
|
|
|
+ }
|
|
|
+ if(item.id==2){//空间新增
|
|
|
+ this.pageStatus = 1;
|
|
|
+ }
|
|
|
+ console.warn("***operateHandle***",item,this.pageStatus)
|
|
|
+ },
|
|
|
+ },
|
|
|
+ };
|
|
|
+</script>
|
|
|
+<style lang="css" scoped>
|
|
|
+ @import "./mapComponent.css";
|
|
|
+</style>
|