/* * @Author: your name * @Date: 2022-01-11 13:45:12 * @LastEditTime: 2022-02-26 13:59:03 * @LastEditors: Please set LastEditors * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @FilePath: /test/hello-world/src/utils/mapClass.js */ import { pipeColor, svgUrl } from "@/utils/mapClass/config.js"; // 编辑类 // 在地图上新增的设备可以直接编辑, // 已经保存完成的设备需要点编辑才可以编辑 export class EditorMap { // 地图的对象实例 map = null; // 父vue的实例 vue = null; // 操作 新建,编辑,删除,编辑跟删除只对已经在图上的设备有效 默认值:0, 新建:1,编辑:2, 删除: 3。 // 新建的时候会把未保存的线条清空 control = 0; // 鼠标事件对象,用来将点跟线上图 mousetool = null; // 当前正在手动绘制的对象 nowMouseTarget = null; // 当线mousetool线被按下的时候的flag 当线被按下的时候为true,就不询问是否删除了 mosueToolPolineDownFlag = false; // 绘制marer的时候的配置,在绘制完挂载事件的时候需要使用 mouseToolMarkerOptions = null; // 绘制poline的时候的配置,在绘制完挂载事件的时候需要使用 mouseToolPolineOptions = null; // 存放所有的设备的数组集合,这是一个对象,对象里面是各种设备的数组 allDevice = {}; // 存放所有的管道 pipeArr = {}; // 当前的infowindow的组件 infowindowComponent = null; // infowindow本身 infowindow = null; constructor(contaienr, config = {}, vue) { this.map = new AMap.Map(contaienr, { viewMode: "3D", center: [114.196007, 38.260288], layers: [AMap.createDefaultLayer()], // layers 字段为空或者不赋值将会自动创建默认底图。 zoom: 14, ...config, }); this.vue = vue; this.init(); } init() { // 地图事件 this.mapEvent(); // 手动点线上图准备,编辑模式 this.mouseAddDevice(); // this.mouseAddMarker(); // this.mouseAddPipeline(); } // map的事件监听 mapEvent() { this.map.on("click", () => { // mousetool对象画出的对象的操作 // 如果有手动绘制对象,要手动清楚一下,因为画线的时候不好清除旧线,这其实是用来清楚旧线的 // 当画出来的线被mousedown,不删除,但是mouseToolPipeLineFlag要归位,在移出线的时候统一归位 // 如果对象是marker,直接删除 if (this.nowMouseTarget?.type == "AMap.Marker") { this.mouseToolDrawClear(); } else { // 当地图上已经画了线,并且没有点在线上,询问是否删除 if (this.nowMouseTarget && !this.mosueToolPolineDownFlag) { this.confirm("是否重新绘制管道", { type: "warning" }) .then(() => { // 删除原来的线 this.mouseToolDrawClear(); // 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的 this.mousetool.polyline(this.mouseToolPolineOptions); }) .catch(() => {}); } } }); this.map.on("moveend", () => { console.log("地图停止移动"); if (this.flag) { console.log("弹框"); this.flag = false; } }); window.panTo = () => { this.flag = true; this.map.panTo([116.428285, 39.886129]); }; } // 弹框工具 confirm(message, obj) { return this.vue.$confirm(message, obj); } // 改变操作状态 changeControl(num) { this.control = num; } // 点线编辑上图准备 mouseAddDevice() { this.map.plugin(["AMap.MouseTool"], () => { this.mousetool = new AMap.MouseTool(this.map); }); // 挂载绘制结束的事件 this.mouseDrawEvent(); } // 点或者线上图结束后触发的事件 mouseDrawEvent() { this.mousetool.on("draw", (e) => { const target = e.obj; // console.log([target._position.lng, target._position.lat]); const { type: targetType } = target; // 当这个点是marker的时候 if (targetType == "AMap.Marker") { this.mouseToolMarkerEvent(target); } else { // 如果是线,挂上编辑 this.lineEditor(target); this.mousetool.close(); this.mouseToolPolineEvent(target); console.log(targetType, "当前对象是管道"); } this.nowMouseTarget = target; }); } // 绘制marker结束后,在marker身上添加的事件 mouseToolMarkerEvent(target) { // 由于画出来的marker点击会换位置,所以当移入的时候删除绘制事件,移出去在增加绘制事件 target.on("mouseover", (e) => { // 鼠标事件关闭 this.mousetool.close(false); }); target.on("mouseout", (e) => { // 这里不方便获取原来的属性,因为position不好解决,还是设置一个值吧 // 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的 this.mousetool.marker(this.mouseToolMarkerOptions); }); // 点 target.on("click", (e) => { // 弹框 }); } // 挂上线以及线的事件 lineEditor(line) { // line.editor && line.editor.close(); // 当前点击次数,1次为编辑,2次为弹框 line.editorNum = 0; line.editor = new AMap.PolyEditor(this.map, line); } // 绘制管道的时候,挂载的事件 mouseToolPolineEvent(target) { // 线按下的时候会变成编辑,mousetool事件会清空 移出线的时候 在把polyline事件加上 target.on("mouseover", (e) => { // 鼠标事件关闭 // this.mousetool.close(false); }); target.on("mouseout", (e) => { // 有时候按在线上移动地图,map点击事件中mosueToolPolineDownFlag无法归位,在这里归位 this.mosueToolPolineDownFlag = false; // 鼠标事件开启,并且赋值原来的属性,this.mouseToolMarkerOptions是开启绘制的时候记录的 // this.mousetool.polyline(this.mouseToolPolineOptions); }); // 线 target.on("mousedown", (e) => { const line = e.target; // mosueTool按下的flag,按在线上,不询问是否删除 this.mosueToolPolineDownFlag = true; // 按下的时候要关闭事件 this.mousetool.close(false); // 如果当前状态不是编辑,则进入编辑状态 if (line.editorNum < 1) { // 打开并且++ line.editor.open(); line.editorNum++; } else { // 这里就要弹框了 console.log(line.getPath()); } }); } // 设备点击上图开启 mouseAddMarker(markerObj = {}) { // 清空已经绘制完的对象 this.mousetoolClose(true); // 记录一下配置项,在挂载点击的时候,需要使用 this.mouseToolMarkerOptions = { draggable: true, ...markerObj, }; this.mousetool.marker(this.mouseToolMarkerOptions); } // 管线点击上图开启 mouseAddPipeline(pipeObj = {}) { this.mousetoolClose(true); // 开始画线 this.mosuetoolPolineFlag = true; this.mouseToolPolineOptions = { strokeWeight: 5, ...pipeObj, }; this.mousetool.polyline(this.mouseToolPolineOptions); } // 手动清除map上绘制的对象 mouseToolDrawClear() { if (this.nowMouseTarget) { this.map.remove(this.nowMouseTarget); // 如果有editor,则关闭 this.nowMouseTarget.editor && this.nowMouseTarget.editor.close(); this.nowMouseTarget = null; } } // 关闭点击上图事件 true清除之前绘制的图像,false 仅关闭上图事件 mousetoolClose(boolean) { // 清空地图上的绘制对象的同时,也要清楚这个nowMouseTarget控制对象 if (this.nowMouseTarget) { // 如果有editor,则关闭 this.nowMouseTarget.editor && this.nowMouseTarget.editor.close(); this.nowMouseTarget = null; } this.mousetool.close(boolean); } /** * * * * * * * 地图上add设备 * * * @description: * @param {*} deviceData marker的数据 * @param {*} compontent marker点击弹出的infowindow的组件 * @return {*} */ addDevice(deviceData, compontent) { const { longitude: lng, latitude: lat, iconType } = deviceData; const icon = svgUrl[iconType]; let device = this.createMarker({ map: this.map, anchor: "bottom-center", icon, position: [lng, lat], extData: deviceData, }); // device.hide(); // 如果没有有这个公司的数组,就创建,有就直接push if (!Array.isArray(this.allDevice[iconType])) { this.allDevice[iconType] = []; } this.allDevice[iconType].push(device); // 设备的事件函数 this.deviceEvent(device, compontent); } deviceEvent(device, compontent) { device.on("click", (e) => { const target = e.target; // 如果control==0就是默认值,没有使用123功能,就显示infowindow if (this.control == 0) { this.markerClick(target, compontent); } else if (this.control == 2) { // 2是已经上图的设备拥有的编辑功能 } else if (this.control == 3) { // 3是删除操作 } }); } /** 点击marker出现infowindow * @description: * @param {*} target 点击的对象 * @param {*} compontent marker点击弹出的infowindow的组件 * @return {*} */ markerClick(target, compontent) { const deviceExtData = target.getExtData(); const { longitude: lng, latitude: lat } = deviceExtData; // 创建一个可以控制的组件,将其dom插入infowindow this.infowindowComponent = this.createInfowindowDom( this.vue, this, deviceExtData, compontent ); // 没恩么用,控制台测试的时候用着玩的 window.func = () => { const { longitude: lng, latitude: lat } = target.getExtData(); const cd = { id: 1, name: "9", lng, lat, }; this.infowindowComponentChange(cd); target.setExtData(cd); }; this.infowindow = new AMap.InfoWindow({ isCustom: true, content: this.infowindowComponent.$el, position: [lng, lat], // anchor: "top-left", // offset: [20, -45], anchor: "middle-left", offset: [20, -10], }); this.infowindow.open(this.map); } // 创建要加入到infowindow里的 createInfowindowDom(vueRoot, mapClass, deviceData, compontent) { const Component = this.vue.$Vue.extend(compontent, {}); return new Component({ data() { return { // 当前vue实例 vueRoot, // 自己写的map类 mapClass, // 数据 deviceData, }; }, }).$mount(); } // 当前显示的infowindow内部的数据发生变化,一般在socket传回数据的时候使用 infowindowComponentChange(data) { this.infowindowComponent.deviceData = data; } // 创建marker createMarker(MarkerOptions) { return new AMap.Marker(MarkerOptions); } // 地图上add管道 addPipeLine(objData, component) { const { path, pipePressure, iconType } = objData; console.log(path); // 根据压力获取颜色 const color = pipeColor[pipePressure + 1]; const pipe = this.createPipeLine({ path: eval(path), strokeWeight: 4, strokeColor: color, extData: objData, cursor: "pointer", }); this.map.add(pipe); console.log(pipe.getExtData()); // pipe.hide(); if (!Array.isArray(this.pipeArr[iconType])) { this.pipeArr[iconType] = []; } this.pipeArr[iconType].push(pipe); // console.log(this.pipeArr); // this.map.panTo([path[0][0], path[0][1]]); this.pipeEvent(pipe, component); } createPipeLine(pipeLineOptions) { return new AMap.Polyline(pipeLineOptions); } pipeEvent(pipe, compontent) { pipe.on("mouseover", (e) => { const target = e.target; // 获取当前颜色 const options = target.getOptions(); options.strokeColor = "blue"; target.setOptions(options); }); pipe.on("mouseout", (e) => { const target = e.target; // 根据管道压力获取颜色 const { pipePressure } = target.getExtData(); const color = pipeColor[pipePressure + 1]; // 获取当前颜色 const options = target.getOptions(); options.strokeColor = color; target.setOptions(options); }); pipe.on("click", (e) => { const target = e.target; target.lnglat = e.lnglat; // 如果control==0就是默认值,没有使用123功能,就显示infowindow if (this.control == 0) { this.pipeClick(target, compontent); } else if (this.control == 2) { // 2是已经上图的设备拥有的编辑功能 } else if (this.control == 3) { // 3是删除操作 } }); } pipeClick(target, compontent) { const deviceExtData = target.getExtData(); const { lng, lat } = target.lnglat; // 创建一个可以控制的组件,将其dom插入infowindow this.infowindowComponent = this.createInfowindowDom( this.vue, this, deviceExtData, compontent ); // 没恩么用,控制台测试的时候用着玩的 // window.func = () => { // const { lng, lat } = target.getExtData(); // const cd = { // id: 1, // name: "9", // lng, // lat, // }; // this.infowindowComponentChange(cd); // target.setExtData(cd); // }; this.infowindow = new AMap.InfoWindow({ isCustom: true, content: this.infowindowComponent.$el, position: [lng, lat], // anchor: "top-left", // offset: [20, -15], anchor: "middle-left", offset: [20, 0], }); this.infowindow.open(this.map); } infowindowClose() { if (!this.infowindow) return; this.infowindow.close(); } allilter(companyArr, typeArr) { for (let pipeItem in this.pipeArr) { this.pipeArr[pipeItem].forEach((pipe) => { const data = pipe.getExtData(); if (companyArr.indexOf(data.companyType + "") >= 0) { pipe.show(); } else { pipe.hide(); } }); } for (let deviceItem in this.allDevice) { this.allDevice[deviceItem].forEach((device) => { const data = device.getExtData(); // 设备过滤受到bigwindow页面的的两种制约,companyArr, typeArr 两个数组制约显示隐藏 // 燃气没有公司,所以没有device.companyType不收到公司的控制 const companyHas = companyArr.indexOf(data.companyType + "") >= 0; // 设备存在 const deviceHas = typeArr.indexOf(data.iconType + "") >= 0; // 必须设备存在数组里,才会显示设备 !data.companyType代表用户不受公司制约 if (deviceHas && (companyHas || !data.companyType)) { device.show(); } else { device.hide(); } }); } } // 根据公司过滤是否显示 公司由一个数组传过来 companyFilter(companyArr) { for (let pipeItem in this.pipeArr) { this.pipeArr[pipeItem].forEach((pipe) => { const data = pipe.getExtData(); if (companyArr.indexOf(data.companyType + "") >= 0) { pipe.show(); } else { pipe.hide(); } }); } for (let deviceItem in this.allDevice) { this.allDevice[deviceItem].forEach((device) => { const data = device.getExtData(); // 燃气没有公司,所以没有device.companyType不收到公司的控制 const companyHas = companyArr.indexOf(data.companyType + "") >= 0; // 必须设备存在数组里,才会显示设备 !data.companyType代表用户不受公司制约 if (companyHas || !data.companyType) { device.show(); } else { device.hide(); } }); } } // 根据设备类型隐藏展示 iconTypeFilter(typeArr) { for (let deviceItem in this.allDevice) { this.allDevice[deviceItem].forEach((device) => { if (typeArr.indexOf(deviceItem + "") >= 0) { device.show(); } else { device.hide(); } }); } } // 公司改变,先调用设备方法,在调用公司方法 companyChange(companyArr, typeArr) { this.iconTypeFilter(typeArr); this.companyFilter(companyArr); } // 设备选择,先调用公司方法,在调用设备方法覆盖 deviceChange(companyArr, typeArr) { this.companyFilter(companyArr); this.iconTypeFilter(typeArr); } // 卫星图切换 satellite = null; changeMap(bool) { // 卫星, if (!bool) { if (this.satellite) return; this.satellite = new AMap.TileLayer.Satellite(); this.map.addLayer(this.satellite); } else { if (this.satellite) { this.map.removeLayer(this.satellite); this.satellite = null; } } } }