<!-- * @Description: 总览地图 * @Author: 王晓颖 * @Date:2021-01-12 09:59:26 --> <template> <div class="container"> <!--数量整体显示--> <div class="top-board"> <div class="board-div"> <div class="board-div-value"> {{ wastebinCount }} </div> <div class="board-div-title"> 垃圾桶 </div> </div> <el-divider direction="vertical"/> <div class="board-div"> <div class="board-div-value"> {{ classificationCount }} </div> <div class="board-div-title"> 分类箱 </div> </div> <div v-show="area!==''"> <el-divider direction="vertical"/> </div> <div v-show="area" class="board-div"> <div class="board-div-value"> {{ area }} km² </div> <div class="board-div-title"> 面积 </div> </div> </div> <!--工具箱--> <tools-container> <!-- 绘制工具--> <draw-tool @click="drawBox" @clear="clearDraw"/> </tools-container> <!--地图--> <map-view @ready="mapInit"> <!--设施显示--> <div> <div v-if="wastebinShow"> <l-marker v-for="(wastebin,index) in wastebins" :key="'wastebin'+index" :icon="wastebinIcon" :lat-lng="wastebin.latlng" @click="openPopup($event,'wastebin',wastebin)"> <l-popup @ready="fetchWastebinDetail"> <popwindow :data="currentData" type="wastebin"/> </l-popup> </l-marker> </div> <div v-if="classificationShow"> <l-marker v-for="(classification,index) in classifications" :key="'classification'+index" :icon="classificationIcon" :lat-lng="classification.latlng" @click="openPopup($event,'classification',classification)"> <l-popup @ready="fetchClassificationDetail"> <popwindow :data="currentData" type="classification"/> </l-popup> </l-marker> </div> </div> </map-view> </div> </template> <script> import MapView from '@/views/mapViews/mapView' import * as L from 'leaflet' import { LMarker, LIcon, LPopup } from 'vue2-leaflet' import Popwindow from './components/popwindow' import { getWastebinList } from '@/api/biz/wastebin' import ToolsContainer from './components/toolsContainer' import DrawTool from './components/drawTool' import 'leaflet.pm' import 'leaflet.pm/dist/leaflet.pm.css' import * as turf from '@turf/turf' export default { name: 'MapOverview', components: { DrawTool, ToolsContainer, Popwindow, MapView, LMarker, LIcon, LPopup }, data() { return { map: null, // 地图 drawLayer: null, // 绘制图层 wastebins: [], // 垃圾桶列表 classifications: [], // 垃圾中转站列表 wastebinCount: 0, classificationCount: 0, wastebinIcon: L.icon({ iconUrl: require('@/assets/overview/wastebin.png'), iconSize: [32, 32], iconAnchor: [16, 32] }), // 垃圾桶图标 classificationIcon: L.icon({ iconUrl: require('@/assets/overview/classification.png'), iconSize: [32, 32], iconAnchor: [16, 32] }), // 分类箱图标 wastebinShow: true, // 垃圾桶是否显示 classificationShow: true, // 分类箱是否显示 currentData: {}, // 当前弹窗数据 area: '' // 选区面积 } }, created() { this.getWastebins() }, methods: { // 地图初始化完毕 mapInit(map) { this.map = map this.map.pm.setLang('zh') }, // 获取垃圾桶列表 getWastebins: function() { // this.wastebins = [ // { id: '12346', name: '李四', latlng: [27.73252, 116.05321], lng: 27.73252, lat: 116.05321, sex: '0', tel: '13382739123', type: '0', typeName: '普通职工', post: '1', jobs: '0', responseArea: '崇仁县', responseAreaName: '崇仁县' }, // { id: '12347', name: '王五', latlng: [27.72852, 116.03721], lng: 27.72852, lat: 116.03721, sex: '0', tel: '13382739123', type: '0', typeName: '普通职工', post: '1', jobs: '1', responseArea: '崇仁县', responseAreaName: '崇仁县' } // ] const params = { offset: 1, limit: 200, sort: '', order: 'desc' } getWastebinList(params).then(response => { if (response.code === 200) { this.wastebins = response.data.filter(item => item.isClassification === 0) this.wastebins = this.wastebins.map(item => { return { ...item, latlng: [parseFloat(item.lat), parseFloat(item.lng)] } }) this.wastebinCount = this.wastebins.length this.classifications = response.data.filter(item => item.isClassification === 1) this.classifications = this.classifications.map(item => { return { ...item, latlng: [parseFloat(item.lat), parseFloat(item.lng)] } }) this.classificationCount = this.classifications.length } }) }, // 获取垃圾桶详情 fetchWastebinDetail(data) { this.currentData = data }, // 获取分类箱详情 fetchClassificationDetail(data) { this.currentData = data }, // 打开弹窗 async openPopup(event, type, data) { switch (type) { case 'wastebin': await this.fetchWastebinDetail(data) break case 'classification': await this.fetchClassificationDetail(data) break } this.$nextTick(() => { event.target.openPopup() }) }, // 移除绘制图层 drawDelete() { if (this.drawLayer) { this.drawLayer.layer.remove() } if (this.map.graphics) { this.map.graphics.forEach(graphic => { this.map.removeLayer(graphic.layer) }) } }, // 绘制选框 drawBox(type) { console.log(this.map) this.drawDelete() this.$nextTick(() => { this.map.pm.enableDraw(type, { snappable: false }) // 绘制完成 this.map.on('pm:create', e => { this.drawLayer = e // debugger // 计算面积 var area if (e.shape === 'Circle') { // 计算面积 const radius = e.layer.options.radius const latlng = e.layer.getLatLng() area = 3.1415926 * radius * radius this.area = (area / 1000000).toFixed(2) const circle = turf.circle([latlng.lng, latlng.lat], radius / 1000) // 依次判断点的存在 let wastbinCount = 0 for (const wastbin of this.wastebins) { if (this.judgePointInCircle(wastbin, circle)) { wastbinCount++ } } let classificationCount = 0 for (const wastbin of this.classifications) { if (this.judgePointInCircle(wastbin, circle)) { classificationCount++ } } this.wastebinCount = wastbinCount this.classificationCount = classificationCount } else { // 获取选区的geojson, 用turf计算面积 const geojson = e.layer.toGeoJSON() area = turf.area(geojson) let wastbinCount = 0 for (const wastbin of this.wastebins) { if (this.judgePointInPolygon(wastbin, geojson)) { wastbinCount++ } } let classificationCount = 0 for (const wastbin of this.classifications) { if (this.judgePointInPolygon(wastbin, geojson)) { classificationCount++ } } this.wastebinCount = wastbinCount this.classificationCount = classificationCount } this.area = (area / 1000000).toFixed(2) console.log('面积' + area.toString()) // 计算区域内的垃圾桶和分类箱个数 }) }) }, judgePointInPolygon(p, geojson) { // 1. 点 const point = turf.point([p.latlng[1], p.latlng[0]]) // 2. 多边形 const polygon = geojson.geometry const result = turf.booleanPointInPolygon(point, polygon) if (result) { console.log('is in polygon') } return result }, // 判断点是否在圆里 judgePointInCircle(p, circle) { // 1. 点 const point = turf.point([p.latlng[1], p.latlng[0]]) const result = turf.booleanPointInPolygon(point, circle) if (result) { console.log('is in circle') } return result }, // 清除绘制 clearDraw() { if (this.drawLayer) { this.drawDelete() } else { this.map.pm.toggleGlobalRemovalMode() } this.area = '' this.wastebinCount = this.wastebins.length this.classificationCount = this.classifications.length } } } </script> <style rel="stylesheet/scss" lang="scss" scoped> .container{ width: 100%; height: calc(100vh - 150px); position: relative; .top-board{ height: 100px; min-width:250px; background-color: #ffffff; position: absolute; z-index:1001; top:10px; left:10px; display: flex; justify-content: space-between; align-items: center; padding:12px; .board-div{ min-width: 80px; font-size:19px; text-align: center; .board-div-value{ padding-bottom: 10px; } .board-div-title{ font-size:17px; } } } .legend-group{ position:absolute; z-index:3000; bottom: 0px; left: 50%; transform: translateX(-50%); display: flex; justify-content: center; background: rgba(82, 82, 82, 0.6); width:100%; padding:10px 10px; .legend-div{ display:flex; align-items: center; margin-right: 20px; .legend-icon{ img{ width:32px; height:32px; margin-right: 10px; } .grey-img{ -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); filter: grayscale(100%); filter: gray; } } .legend-text{ line-height: 32px; color:white; font-weight: bold; font-size:0.9rem; } } .legend-div:hover{ cursor:pointer; } } } </style>