最全vue的vue-amap使用高德地图插件画多边形范围
一、在vue-cli的框架下的main.js(或者main.ts)中引入高德插件,代码如下:
import Vue from 'vue'
import VueAMap from 'vue-amap'
import ElementUI from 'element-ui'
import App from './App.vue'
import router from './router'
import store from './store'
import './registerServiceWorker'
Vue.use(VueAMap)
Vue.use(ElementUI)
VueAMap.initAMapApiLoader({
// 高德的key
key: '你的高德key',
// 插件集合
plugin: [
'AMap.Autocomplete',
'AMap.PlaceSearch',
'AMap.Scale',
'AMap.OverView',
'AMap.ToolBar',
'AMap.MapType',
'AMap.PolyEditor',
'AMap.CircleEditor',
'AMap.Geocoder',
'AMap.Geolocation'
],
// 高德 sdk 版本,默认为 1.4.4
v: '1.4.10'
})
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
第三种画多边形的效果图:
注意:1、这种画多边形,开始就需要一个初始的多边形;
2、所以,输入要画多边形范围的地名,点击搜索,地图会跳转到搜索的地方,同时得到经纬度;
3、点“范围绘制”时,我再方法里根据第2步的经纬度,初始了一个多边形;
****隐藏彩蛋****
下图的 “请输入经纬度” 可以输入一大组的经纬度,按回车键,也可以画出多边形,在按“范围绘制”也可以更改;(格式如下:)
这个格式就是复制的地图上显示的经纬度坐标
106.2246 , 29.59258 106.225064 , 29.593287 106.226137 , 29.593558 106.22692 , 29.593083
二、第一种画化:使用Geolocation画多边形(效果是在地图点了,才会形成多边形)
// 新增 编辑 查看 <template> <div class="point"> <el-header></el-header> <div class="action-bar"> <el-form class="inline-form" :rules="rules" ref="formData" size="small" :model="formData"> <el-form-item label label-width="220" prop="location"> <el-input :disabled="!ifFalg" class="name-input" clearable v-model="formData.location" placeholder="名称" maxlength="30" ></el-input> </el-form-item> <el-form-item label prop="longitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.longitude" placeholder="经度 " ></el-input> </el-form-item> <el-form-item label prop="latitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.latitude" placeholder="纬度" ></el-input> </el-form-item> <el-button class="my-button" v-if="ifFalg" type="primary" @click="save" size="small">保存</el-button> <el-button class="my-button" size="small" @click="close">关闭</el-button> </el-form> </div> <div class="map-box"> <div class="map-tool"> <div v-if="ifFalg"> <el-checkbox v-model="enterType">地图上描点</el-checkbox> </div> <!-- <el-checkbox @change="checkbox" v-model="enterType">地图上描点</el-checkbox> --> <div class="longlat"> <ul> <li v-for="(item, index) in lnglatpoints" :key="index"> {{item.longitude}} , {{item.latitude}} <i v-if="ifFalg" class="el-icon-close" @click="deletes(item)" ></i> </li> </ul> <el-input v-if="ifFalg" class="my-input" size="small" clearable v-model="lngLat" @keyup.enter.native="submitEnter" placeholder="请输入经纬度" ></el-input> <el-button v-if="ifFalg" size="small" @click="clear" type="primary" class="claer">清除</el-button> </div> </div> <div class="map" id="map"> <el-amap ref="map" bubble :plugin="plugin" :zoom="map.zoom" :center="map.center" :events="events" id="amap" > <el-amap-polygon :events="plugin.events" :path="path" :draggable="draggable" fillColor="#2b83f9" fillOpacity="0.5" strokeWeight="0" strokeColor="#2b83f9" strokeOpacity="0.5" ></el-amap-polygon> <!-- <el-amap-marker :position="marker.position" :events="plugin.events"></el-amap-marker> --> <el-amap-marker v-if="formData.type === 1" :position="map.center" :label="label"></el-amap-marker> </el-amap> </div> </div> </div> </template> <script lang="ts"> import * as api from '@/utils/api/index' import { Component, Vue } from 'vue-property-decorator' import eHeader from '@/components/header.vue' import { constants } from 'http2' import * as util from '@/utils/util.ts' const testLongitude = (rule: any, value: string, callback: Function) => { if (util.regExp.longitudeRegExp.test(value)) { return callback() } else { return callback(new Error('请输入正确的经度')) } } const testLatitude = (rule: any, value: string, callback: Function) => { if (util.regExp.latitudeRegExp.test(value)) { return callback() } else { return callback(new Error('请输入正确的纬度')) } } @Component({ components: { 'el-header': eHeader } }) export default class point extends Vue { private breadcrumbId = 0 private id = '' private lngLat = '' private ifFalg = true private map = { zoom: 15, center: [106.55073, 29.56471] } private path: any = [] private draggable = false private lnglatpoints: any = [] private enterType = false // 录入坐标 | 地图上描点 private cities = [] private formData = { location: '', longitude: '', latitude: '' } plugin = { pName: 'Geolocation', events: {} } events = {} private test = 1 private rules = { location: [ { required: true, message: '请输入接送点名称', trigger: 'blur' } ], longitude: [{ validator: testLongitude, trigger: 'blur' }], latitude: [{ validator: testLatitude, trigger: 'blur' }] } mounted() { this.id = this.$route.params.id this.breadcrumbId = Number(this.$route.query.breadcrumbId) if (this.breadcrumbId === 2) { this.ifFalg = false } if (this.id !== '-1') { this.details() } // this.city() let _this: any = this // 地图点击事件 _this.events = { click: (e: any) => { if (this.enterType) { this.path = [] console.log(e.lnglat) let lnglat = e.lnglat this.lnglatpoints.push({ latitude: lnglat.lat, longitude: lnglat.lng }) console.log(this.lnglatpoints) this.lnglatpoints.map((val: any, index: number) => { console.log(index) if (index === 0) { this.map.center = [val.longitude, val.latitude] } let arr = [val.longitude, val.latitude] this.path.push(arr) }) // this.setFitView() } } } // 多边形点击事件 _this.plugin.events = { click: (e: any) => { if (this.enterType) { this.path = [] console.log(e.lnglat) let lnglat = e.lnglat this.lnglatpoints.push({ latitude: lnglat.lat, longitude: lnglat.lng }) console.log(this.lnglatpoints) this.lnglatpoints.map((val: any, index: number) => { console.log(index) if (index === 0) { this.map.center = [val.longitude, val.latitude] } let arr = [val.longitude, val.latitude] this.path.push(arr) }) // this.setFitView() } } } }// 获取接送范围集合 details() { const loading = this.$loading({ lock: true, text: '加载中...' }) api.main.boss_line_point__get({ params: {param: this.id}}).then((res: any) => { if (res.data.success) { const response = res.data.data this.formData = response let points = res.data.data.points if (points != null) { for (let i = 0; i < points.length; i++) { points[i].id = i } this.lnglatpoints = points this.lnglatpoints.map((val: any, index: number) => { if (index === 0) { this.map.center = [val.longitude, val.latitude] } let arr = [val.longitude, val.latitude] this.path.push(arr) }) } else { this.map.center = [ Number(this.formData.longitude), Number(this.formData.latitude) ] this.label.content = this.formData.location } setTimeout(this.setFitView, 0) } else { this.$message.error(res.data.message) } loading.close() }) } // 移除经纬度 deletes(data: any) { let e: any = this this.path = [] for (let i = 0; i < e.lnglatpoints.length; i++) { if ( data.latitude === e.lnglatpoints[i].latitude && data.longitude === e.lnglatpoints[i].longitude ) { e.lnglatpoints.splice(i, 1) } } console.log(e.path) this.lnglatpoints.map((val: any, index: number) => { let arr = [val.longitude, val.latitude] this.path.push(arr) if (index === 0) { this.map.center = [val.longitude, val.latitude] } console.log(this.path) }) } clear() { this.$confirm('确认删除绘制的接送区域?', '删除', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(() => { let self: any = this this.path = [] this.lnglatpoints = [] // this.map.center = [106.5507300000, 29.5647100000] this.lngLat = '' self.formData.points = [] }) .catch(() => {}) } // 输入经纬度 submitEnter() { // eslint-disable-next-line const illegalRegExp = /^(\D|\d*\.?\d*,*\s)|[^\d\s,\.]|^\d*\.?\d*$|(,\.|\.,)+|(\d*\.*\d*,){2,}|(\d*\.){2,}|(\d*\s){2,}|(\s\d*\.?\d*|\D)$/g const replaceWhiteSpaceRegExp = /(?<=(,|\.|\s))\s+|\s+(?=(,|\.))|^\s|\s+$/g this.lngLat = this.lngLat.replace(replaceWhiteSpaceRegExp, '') if (illegalRegExp.test(this.lngLat)) { return this.$message.error('经纬度格式错误!') } const lnglatArray = this.lngLat.split(' ') lnglatArray.forEach(lnglatString => { const lnglatObject = { longitude: lnglatString.split(',')[0], latitude: lnglatString.split(',')[1] } this.lnglatpoints.push(lnglatObject) }) this.path = [] this.lnglatpoints.map((val: any, index: number) => { let arr = [val.longitude, val.latitude] this.path.push(arr) this.lngLat = '' if (index === 0) { this.map.center = [val.longitude, val.latitude] } }) } setFitView() { const vm: any = this let map = vm.$refs.map.$$getInstance() map.setFitView() } close() { this.$router.push({ name: 'pointList' }) } save() { let e: any = this let params: any = {} if (this.id !== '-1') { // 编辑 e.formData.id = this.id params.id = this.id } e.formData.points = this.lnglatpoints if (e.formData.location === '' || e.formData.location === null) { this.$message.warning('名称不能为空!') return } if (this.lnglatpoints.length < 3 && e.formData.type === 2) { this.$message.warning('经纬度不能小于三组!') return } params.points = this.lnglatpoints params.location = this.formData.location params.longitude = this.formData.longitude params.latitude = this.formData.latitude if (this.id !== '-1') { api.main.boss_line_point_update_post({ data: params }).then((res: any) => { if (res.data.success) { this.$message.success('保存成功!') this.$router.push({ name: 'pointList' }) } else { this.$message.error(res.data.message) } }) } else { api.main .boss_line_point_addAndBindLine_post({ data: params }) .then((res: any) => { if (res.data.success) { this.$message.success('保存成功!') this.$router.push({ name: 'pointList' }) } else { this.$message.error(res.data.message) } }) } } } </script> <style lang="scss" scoped> ul, li { list-style: none; margin: 0; padding: 0; } .inline-form { display: flex; display: -webkit-flex; flex-direction: row; flex-wrap: wrap; .el-form-item { margin-bottom: 10px; margin-left: 15px; display: flex; } .el-button { margin-left: 15px; height: 32px; } } .action-bar { box-sizing: border-box; padding: 10px; padding-bottom: 0; border: { top: 1px solid #ddd; bottom: 1px solid #ddd; } .my-input { width: 150px; } .name-input { width: 260px; } } .el-select-dropdown__item { background-color: white; text-indent: 10px; } .claer { margin-top: 15px; float: right; } $map_height: calc(100vh - 55px - 50px - 75px - 15px); .map-box { position: relative; height: $map_height; .map-tool { position: absolute; width: 220px; z-index: 170; top: 0; left: 0; max-height: 100%; box-sizing: border-box; padding: 10px; overflow-y: auto; background-color: #fff; box-shadow: 2px 4px 7px 1px #dedede; } .map { transition: all 0.6s; position: absolute; top: 0; right: 0; bottom: 0; left: 0; } } .swiper-box { position: relative; z-index: 161; display: flex; align-items: center; flex-direction: row; justify-content: center; width: 100%; transition: transform ease-in 0.6s; transform: translateX(0); white-space: nowrap; .swiper-item { width: 100%; height: $map_height; } } .hide-text-area { transform: translateX(-100%); } .gray-map { filter: grayscale(90%); } .longlat { margin-top: 15px; padding-bottom: 15px; ul { li { padding: 6px; background-color: #ddd; border-radius: 4px; margin-bottom: 15px; font-size: 14px; color: #666; position: relative; } } } .el-icon-close { display: inline-block; position: absolute; right: 10px; color: #000 !important; cursor: pointer; } .my-button { margin-bottom: 10px; } </style>
三、第二种画化:使用AMap.MouseTool画多边形(效果是:多边形随鼠标左键点击,多边形直接跟着变化)
// 新增 编辑 查看 <template> <div class="point"> <el-header></el-header> <div class="action-bar"> <el-form class="inline-form" :rules="rules" ref="formData" size="small" :model="formData"> <el-form-item label prop="location"> <el-input :disabled="!ifFalg" class="name-input" clearable v-model="formData.location" placeholder="名称" maxlength="30" ></el-input> </el-form-item> <el-form-item label prop="longitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.longitude" placeholder="经度 " ></el-input> </el-form-item> <el-form-item label prop="latitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.latitude" placeholder="纬度" ></el-input> </el-form-item> <el-button class="my-button" v-if="ifFalg" type="primary" @click="save" size="small">保存</el-button> <el-button class="my-button" size="small" @click="close">关闭</el-button> </el-form> </div> <div class="map-box"> <div class="map-tool"> <div v-if="ifFalg"> <el-checkbox >地图上描点</el-checkbox> </div> <div class="longlat"> <ul><li v-for="(item, index) in lnglatpoints" :key="index"> {{item.longitude}} , {{item.latitude}} <i v-if="ifFalg" class="el-icon-close" @click="deletes(item)" ></i> </li> </ul> <br> <div> <span >输入范围经纬度:</span> <el-input type="textarea" autosize placeholder="请输入内容" v-model="lnglatpointsString"> </el-input> </div> <el-button v-if="ifFalg" size="small" @click="clear1" type="primary" class="claer1">确定</el-button> <el-button v-if="ifFalg" size="small" @click="clear" type="primary" class="claer">清除</el-button> </div> </div> <div class="map" id="map"> <el-amap ref="map" bubble :zoom="map.zoom" :center="map.center" :events="mapEvents" id="amap" > <el-amap-polygon :events="plugin.events" :path="path" fillColor="#2b83f9" fillOpacity="0.5" strokeWeight="0" strokeColor="#2b83f9" strokeOpacity="0.5" ></el-amap-polygon> <el-amap-marker v-if="formData.type === 1" :position="map.center" :label="label"></el-amap-marker> </el-amap> </div> <div class="my-tools"> <el-row> <el-button type="primary" v-if="ifFalg" @click="drawPolygon()">鼠标绘制</el-button> <el-button type="primary" v-if="ifFalg" @click="polygonEditor.close()">结束编辑</el-button> </el-row> </div> </div> </div> </template> <script lang="ts">同上 /** * 绘制多边形 */ private drawPolygon () { let vm: any = this let map = vm.$refs.map.$$getInstance() map.plugin(['AMap.MouseTool'], function () { var mouseTool = new AMap.MouseTool(map) var drawPolygon = mouseTool.polygon() AMap.event.addListener(mouseTool, 'draw', function (e: any) { e.obj.Je.visible = false let path = e.obj.getPath() vm.drawPolygonsToMap(path) path.forEach((point:any) => { vm.lnglatpoints.push({ latitude: point.lat, longitude: point.lng }) }); // vm.mapDates =path // e.obj.hide() mouseTool.close() }) }) } 同上 } </script> <style lang="scss" scoped> 和上面一样 </style>
三、第三种画化:使用AMap.Polygon和AMap.PolyEditor画多边形(推荐,效果是:https://lbs.amap.com/api/javascript-api/example/overlayers/polygon-draw-and-edit)
注意哦:1、以为这种画多边形,先需要3个点来确定初始的多边形,所以添加了一个功能:搜索 (功能:点击搜索名称的经纬度;);
2、然后我再 ‘范围绘制’ 的方法里根据“搜索”得来的经纬度,手动的弄了3个经纬度数组。
3、然后就可以快乐的画图了。(这画图是真的方便,特别是画范围很复杂的)
// 新增 编辑 查看 <template> <div class="point"> <el-header></el-header> <div class="action-bar"> <el-form class="inline-form" :rules="rules" ref="formData" size="small" :model="formData"> <el-form-item label prop="location"> <el-input :disabled="!ifFalg" class="name-input" clearable v-model="formData.location" placeholder="名称" maxlength="30" ></el-input> </el-form-item>
<el-button class="my-button" type="info" @click="getLocation" size="small">搜索</el-button>
<el-form-item label prop="longitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.longitude" placeholder="经度 " ></el-input> </el-form-item> <el-form-item label prop="latitude"> <el-input :disabled="!ifFalg" class="my-input" clearable v-model.number="formData.latitude" placeholder="纬度" ></el-input> </el-form-item> <el-button class="my-button" v-if="ifFalg" type="primary" @click="save" size="small">保存</el-button> <el-button class="my-button" size="small" @click="close">关闭</el-button> </el-form> </div> <div class="map-box"> <div class="map-tool"> <div v-if="ifFalg"> <el-checkbox >地图上描点</el-checkbox> </div> <div class="longlat"> <ul> <li v-for="(item, index) in lnglatpoints" :key="index"> {{item.longitude}} , {{item.latitude}} <i v-if="ifFalg" class="el-icon-close" @click="deletes(item)" ></i> </li> </ul> <br> <div> <span >输入范围经纬度:</span> <el-input type="textarea" autosize placeholder="请输入内容" v-model="lnglatpointsString"> </el-input> </div> <el-button v-if="ifFalg" size="small" @click="clear1" type="primary" class="claer1">确定</el-button> <el-button v-if="ifFalg" size="small" @click="clear" type="primary" class="claer">清除</el-button> </div> </div> 同上 <div class="my-tools"> <el-row> <el-button type="primary" v-if="ifFalg" @click="drawPolygon()">鼠标绘制</el-button> <el-button type="primary" v-if="ifFalg" @click="polygonEditor.close()">结束编辑</el-button> </el-row> </div> </div> </div> </template> <script lang="ts"> 同上
//画多边形
private drawPolygon(){
let vm: any = this
if (vm.formData.location === '' || vm.formData.location === null) {
this.$message.warning('请先输入名称,才能开始画范围!')
return
}
let map = new AMap.Map("map", {
center:[106.55073, 29.56471],
zoom: 15
});
// 多边形覆盖物节点坐标数组
let polygonArr:any = []
let lng = Number(this.formData.longitude)
let lat = Number(this.formData.latitude)
if(vm.path.length > 0){
polygonArr = vm.path
}else{
polygonArr.push([lng, lat])
polygonArr.push([lng, lat - 0.001])
polygonArr.push([lng - 0.001, lat - 0.001])
}
//使用 AMap.Polygon构建多边形
let polygon = new AMap.Polygon({
path:polygonArr,
strokeColor: "#FF33FF",
strokeWeight: 6,
strokeOpacity: 0.2,
fillOpacity: 0.4,
fillColor: '#1791fc',
zIndex: 50,
})
//将多边形增加到地图上
map.add(polygon)
// 缩放地图到合适的视野级别
map.setFitView([ polygon ])
//构造折线编辑对象,并开启折线的编辑状态
map.plugin(["AMap.PolyEditor"],function(){
let polygonEditor = new AMap.PolyEditor(map,polygon);
vm.polygonEditor =polygonEditor
polygonEditor.open();
//关闭多边形编辑polygonEditor.close()触发该方法;
polygonEditor.on('end', function(event:any) {
// event.target 即为编辑后的多边形对象,event.target.getPath()得到编辑完成后的点数组
let pointArr = event.target.getPath()
vm.lnglatpoints = []
pointArr.forEach((point:any)=>{
vm.lnglatpoints.push({latitude: point.lat,longitude: point.lng})
})
vm.path = []
vm.lnglatpoints.map((val: any, index: number) => {
let arr = [val.longitude, val.latitude]
vm.path.push(arr)
if (index === 0) {
vm.map.center = [val.longitude, val.latitude]
}
})
})
});
}
/**
* 地理编码(地址 -> 坐标)
*/
private getLocation () {
let loc = this.formData.location
AMap.plugin('AMap.Geocoder', () => {
let geocoder = new AMap.Geocoder()
geocoder.getLocation(loc, (status: string, result: any) => {
if (status === 'complete' && result.info === 'OK') {
let { lat, lng } = result.geocodes[0].location
if (lat && lng) {
this.map.center = [lng, lat]
this.formData.longitude=lng
this.formData.latitude=lat
}
}
})
})
}
同上 } </script> <style lang="scss" scoped> 和上面一样 </style>
123