<template> <div style="margin-top: -30px; margin-bottom: -10px;"> <el-row :gutter="20"> <el-col v-show="showpoi" :span="8"> <el-input v-model="keywords" size="small" type="text" placeholder="兴趣点关键字" clearable style="width: 50%" /> <el-button type="primary" size="small" @click="queryOnMap">查询</el-button> <el-button type="info" size="small" @click="clearMap"> 清除地图 </el-button> </el-col> <el-col :span="8" style="text-align: right"> <el-radio-group v-model="queryEventSwitch" size="small" @change="switchEventOrComponent"> <el-radio-button label="1">事件定位</el-radio-button> <el-radio-button label="0">部件定位</el-radio-button> <!-- <el-radio-button v-show="showpoi" label="2">兴趣点属性</el-radio-button>--> </el-radio-group> </el-col> <el-col v-if="queryEventSwitch === '0'" :span="8" style="text-align: right;"> <el-select v-model="form.componentId" placeholder="选择部件" clearable value="" size="small"> <el-option v-for="item in compListOpts" :key="item.value" :label="item.name" :value="item.value"/> </el-select> <el-button type="primary" size="small" @click="checkComponentPoint"> 部件提交 </el-button> </el-col> <el-col v-if="queryEventSwitch === '1'" :span="8" :offset="0" style="text-align: right;"> <el-button type="primary" size="small" @click="checkEventPoint"> 事件提交 </el-button> </el-col> </el-row> <div id="map" ref="mapDiv" class="baseMap"/> </div> </template> <script> import L from 'leaflet' import 'leaflet/dist/leaflet.css' import { mapGetters } from 'vuex' import { merchantListPage } from '@/api/geoCoding/geoCoding' import {getPartsTypeName} from "../../utils/constant"; const esri = require('esri-leaflet') const icon = L.icon({ iconUrl: require('@/assets/icons/icon-position.png'), iconSize: [32, 32], iconAnchor: [16, 32], popupAnchor: [0, -32] }) const poiIcon = L.icon({ iconUrl: require('@/assets/icons/icon-poi.png'), iconSize: [16, 16], iconAnchor: [8, 16], popupAnchor: [0, -16] }) const deltaLng10 = 0.00002536 // 10米范围经度值偏移量(大约) const deltaLat10 = 0.00002256 // 10米范围纬度值偏移量(大约) export default { name: 'LeafletMap', data() { return { map: null, baseLayer: [], markers: [], // 选点 pois: [], // 兴趣点结果 layers: { bjPoint: '', // 部件点图层 grid: '', // 单元网格图层 shopPoint: '' // 商铺图层 }, form: { longitude: '', // 定位点经度 latitude: '', // 定位点纬度 communityId: '', // 社区ID communityName: '', // 社区名称 gridId: '', // 单元网格ID componentId: '', // 部件ID componentName: '' // 部件名称 }, // 主页面返回值 showpoi: true, keywords: '', // 查询关键字 limit: 100, // 兴趣点查询的最大结果数 showEventPointPopup: true, // 是否显示事部件的popup queryEventSwitch: '1', // 1==查询事件;0==查询部件 compListOpts: [] // 部件选择下拉框option } }, computed: { ...mapGetters([ 'baseUrl', 'partsUrl', 'mapUrl', 'gridUrl', 'partsAllUrl' ]) }, mounted() { this.initMap() }, methods: { initMap() { const map = L.map(this.$refs.mapDiv, { minZoom: 14, maxZoom: 25, center: this.baseConfig.center, zoom: this.baseConfig.zoom, zoomControl: false, attributionControl: false, crs: L.CRS.EPSG3857 }) map.doubleClickZoom.disable() this.map = map // data上需要挂载 window.map = map // 加载图层 this.addLayers() const that = this map.on('click', function(e) { that.clearMarkers() // 清除定位点,不清除查询出来的兴趣点 // 加载定位点 if (that.showEventPointPopup) { const pos = L.marker(e.latlng, { icon: icon }) that.markers.push(pos) that.map.addLayer(pos) // 飞到定位点 let zoom = that.map.getZoom() if (zoom < 18) { zoom = 18 } that.map.flyTo(e.latlng, zoom) // 查询所点的网格 const query = that.layers.grid.query() query.nearby(e.latlng, 10) query.run(function(error, featureCollection, response) { if (error) { console.log(error) return } const result = featureCollection.features[0].properties // 赋值 that.form.longitude = e.latlng.lng that.form.latitude = e.latlng.lat that.form.gridId = result.GBID that.form.communityId = result.GBID.substring(0, 12) that.form.communityName = result.Note if (that.queryEventSwitch === '1') { // 事件定位 // 弹出事件点位信息 const popupStr = '<div class="popup-div">' + '<div class="popup-title">事件点</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item"><label>坐标</label>' + that.form.longitude.toFixed(4) + ', ' + that.form.latitude.toFixed(4) + '</div>' + '<div class="popup-item"><label>所在社区</label>' + that.form.communityName + '</div>' + '<div class="popup-item"><label>网格编号</label>' + that.form.gridId + '</div>' + '</div>' pos.bindPopup(popupStr).openPopup() } else if (that.queryEventSwitch === '0') { // 部件定位 // 1构建部件查询多边形,上下左右四个点 const latlngs = [] const p1 = [e.latlng.lat + deltaLat10, e.latlng.lng] // 上方点 const p2 = [e.latlng.lat, e.latlng.lng + deltaLng10] // 右侧点 const p3 = [e.latlng.lat - deltaLat10, e.latlng.lng] // 下方点 const p4 = [e.latlng.lat, e.latlng.lng - deltaLng10] // 左侧点 latlngs.push(p1) latlngs.push(p2) latlngs.push(p3) latlngs.push(p4) const polyline = L.polygon(latlngs) const bjQuery = that.layers.bjPoint.query() bjQuery.within(polyline) bjQuery.run(function(error, featureCollection, response) { if (error) { console.log(error) return } // 查询到结果 if (featureCollection.features.length > 0) { const result = featureCollection.features // 赋值 that.compListOpts = [] // 构建弹出窗口信息 let popupStr = '<div class="popup-div">' + '<div class="popup-title">部件</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item">坐标[' + e.latlng.lng.toFixed(4) + ', ' + e.latlng.lat.toFixed(4) + ']附近的部件有</div>' + '<div class="popup-item"><label>所在社区</label>' + that.form.communityName + '</div>' + '<div class="popup-item"><label>网格编号</label>' + that.form.gridId + '</div>' result.forEach((item, index) => { const dlCode = item.properties.objid.substring(6, 8) const xlCode = item.properties.objid.substring(8, 10) popupStr += '<div class="popup-subitem"><label style="padding-right: 5px;">部件' + (index + 1) + '</label>' + getPartsTypeName(dlCode, xlCode) + '[' + item.properties.objid + ']</div>' const comp = {} comp.name = '部件' + (index + 1) + ':' + getPartsTypeName(dlCode, xlCode) + '[' + item.properties.objid + ']' comp.value = item.properties.objid that.compListOpts.push(comp) }) popupStr += '</div>' pos.bindPopup(popupStr).openPopup() } else { that.$message({ message: '没有查询到部件,请重新定位', type: 'warning' }) } }) } }) } }) }, addLayers() { // 加载天地图底图和标注 this.baseLayer.push(L.tileLayer(this.baseConfig.mapUrl).addTo(this.map)) this.baseLayer.push(L.tileLayer(this.baseConfig.labelUrl).addTo(this.map)) // 加载底图 esri.dynamicMapLayer({ url: `${this.baseUrl}${this.mapUrl}`, zIndex: 1 }).addTo(this.map) // 初始化部件图层(不分层),待切换到部件定位时加载 this.layers.bjPoint = esri.featureLayer({ url: `${this.baseUrl}${this.partsAllUrl}`, minZoom: 19 }) // 加载网格图层,用于选择网格 this.layers.grid = esri.featureLayer({ url: `${this.baseUrl}${this.gridUrl}` }) }, switchEventOrComponent: function() { // 如果选中的是事件定位(1)或部件定位(0),点击地图时弹出事件或者部件的popup;否则(2以上)显示兴趣点结果的属性popup this.showEventPointPopup = this.queryEventSwitch < 2 this.clearPoints() if (this.queryEventSwitch === '0') { // 加载和显示部件图层 this.map.addLayer(this.layers.bjPoint) // 清空部件选择的列表 this.compListOpts = [] } else { this.map.removeLayer(this.layers.bjPoint) } }, clearPoints() { this.clearMarkers() this.clearPois() }, clearPois: function() { const that = this this.pois.forEach(marker => { that.map.removeLayer(marker) }) }, clearMarkers: function() { const that = this this.markers.forEach(marker => { that.map.removeLayer(marker) }) }, queryOnMap: function() { const that = this merchantListPage({ keyword: this.keywords, limit: this.limit }).then(response => { if (response.code === 200) { console.log(response) this.clearPois() // 清除查询的兴趣点结果,不清除地图选点 const data = response.data if (data.total === 0) { this.$message.warning('未找到 "' + that.keywords + '" 的兴趣点,请重新查询') } else if (data.total > that.limit) { this.$message.warning('"' + that.keywords + '" 的兴趣点结果过多,请重新查询') } else { let minLng = data.rows[0].pointX let minLat = data.rows[0].pointY let maxLng = data.rows[0].pointX let maxLat = data.rows[0].pointY data.rows.forEach(item => { const popupStr = '<div class="popup-div">' + '<div class="popup-title">兴趣点</div>' + '<div class="dashed-line"></div>' + '<div class="popup-item"><label>名称</label>' + item.merchantName + '</div>' + '<div class="popup-item"><label>详细地址</label>' + item.address + '</div>' + '</div>' const poi = L.marker([item.pointY, item.pointX], { icon: poiIcon }) poi.bindPopup(popupStr).openPopup() that.pois.push(poi) that.map.addLayer(poi) // 查找左上角和右下角的坐标 if (minLng > item.pointX) minLng = item.pointX if (minLat > item.pointY) minLat = item.pointY if (maxLng < item.pointX) maxLng = item.pointX if (maxLat < item.pointY) maxLat = item.pointY }) const topLeft = L.latLng(maxLat, minLng) // 左上角经纬度 const bottomRight = L.latLng(minLat, maxLng) // 右下角经纬度 const bounds = L.latLngBounds(topLeft, bottomRight) // 定位到矩形 that.map.fitBounds(bounds) } } }) }, // 返回事件定位的结果 checkEventPoint: function() { this.$emit( 'closeMapQueryDialogByEvent', this.form.longitude, this.form.latitude, this.form.communityId, this.form.communityName, this.form.gridId) this.clearPoints() }, // 返回部件定位的结果 checkComponentPoint: function() { this.$emit( 'closeMapQueryDialogByComp', this.form.longitude, this.form.latitude, this.form.communityId, this.form.communityName, this.form.gridId, this.form.componentId) this.clearPoints() }, clearMap() { this.clearPoints() // 清除data属性值 this.keywords = '' this.showEventPointPopup = true // 是否显示事部件的popup this.queryEventSwitch = '1' // 1==查询事件;0==查询部件 this.compListOpts = [] // 部件选择下拉框option this.form.longitude = '' // 定位点经度 this.form.latitude = '' // 定位点纬度 this.form.communityId = '' // 社区ID this.form.communityName = '' // 社区名称 this.form.gridId = '' // 单元网格ID this.form.componentId = '' // 部件ID this.form.componentName = '' // 部件名称 } } } </script> <style scoped> .baseMap { height: 65vh; width: 100%; margin-top: 10px; border: 1px solid #DCDCDC; border-radius: 4px; } </style> <style> .leaflet-container a.leaflet-popup-close-button { top: 5px; /* 修改弹窗关闭按钮样式 */ right: 10px; /* 修改弹窗关闭按钮样式 */ } .leaflet-popup-content .popup-div { font-size: 15px; padding: 6px; } .leaflet-popup-content .popup-title { font-weight: bold; } .leaflet-popup-content .dashed-line { border-bottom: 1px dashed #dddddd; margin: 10px -10px; } .leaflet-popup-content .popup-item { padding-bottom: 6px; } .leaflet-popup-content .popup-item label { font-weight: bold; padding-right: 15px; } .leaflet-popup-content .popup-subitem { padding-bottom: 6px; font-size: 12px; } </style>