背景
最近项目中需要在地图上进行电子围栏的绘制和编辑,这里将实现的思路给大家分享下。由于uniapp官方提供的map组件功能不全,还有在APP端(非nvue)还存在层级问题,所以这里就不考虑使用官方map组件,而是使用renderjs来实现。renderjs中如何使用地图可以参考uniapp地图开发(APP,H5)之前这一篇文章。
在开始实现之前,我们先看下效果图
实现思路
1、我们首先需要在页面展示地图底板
2、DOM中添加四个操作按钮
3、监听地图点击事件,以地图中心点和点击点为两个点生成多边形
4、实现清除、编辑、保存、确定等按钮逻辑
代码实现
其实我们写代码是要先有思路,我们的代码也是根据上面的思路来分步来实现。
接下来就直接上主逻辑页面代码(second.vue)。
<template>
<div id='container' class="map" :style="'height:'+maph+'px'">
<view :originPolygon="originPolygon" :change:originPolygon="renderJS.receiveOriginPolygon" />
</div>
</template>
<script>
export default {
data() {
return {
maph: 0,
//如果需要编辑多边形,传进来多边形字符串
originPolygon: '',
polygon: []
}
},
onLoad(option) {
this.maph = uni.getSystemInfoSync().windowHeight
this.originPolygon = option.polygon || ''
},
methods: {
polygonSave(result) {
this.polygon = result
const eventChannel = this.getOpenerEventChannel();
eventChannel.emit('polygonResult',{
result: JSON.stringify(this.polygon)
})
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<script module="renderJS" lang="renderjs">
let map = null
//是否编辑模式
let isEditMode = false
//其他页面传入的多边形,用作多边形编辑
let originPolygon = null
//多边形的关键点
let path = []
//多边形编辑器
let polygonEditor = null
let ownerInstance = null
//选定并保存好的多边形
let polygonSave = []
//编辑还未保存的多边形
let polygonSaveTemp = []
let that
export default {
data() {
return {
}
},
mounted() {
that = this
window._AMapSecurityConfig = {
securityJsCode: '高德申请的securityJsCode',
}
if (typeof window.AMap == 'function') {
this.initAmap();
} else {
// 动态引入较大类库避免影响页面展示
const script = document.createElement('script');
script.src = 'https://webapi.amap.com/maps?v=2.0&key=高德申请的key';
script.onload = this.initAmap.bind(this);
document.head.appendChild(script);
}
},
//页面卸载清空
unmounted() {
map.clearMap()
map = null
//是否编辑模式
isEditMode = false
//其他页面传入的多边形,用作多边形编辑
originPolygon = null
//多边形的关键点
path = []
//多边形编辑器
polygonEditor = null
ownerInstance = null
//选定并保存好的多边形
polygonSave = []
//编辑还未保存的多边形
polygonSaveTemp = []
that = null
},
methods: {
//获取到传进来的多边形
receiveOriginPolygon(newValue, oldValue, ownerVm, vm) {
if (!ownerInstance) {
ownerInstance = ownerVm
}
if(!newValue){
return
}
originPolygon = JSON.parse(newValue)
isEditMode = true
},
initAmap(e, ownerVm) {
map = new AMap.Map("container", {
zoom: 12, //设置地图显示的缩放级别
viewMode: '2D' //设置地图模式
});
map.on('click', (e) => {
if (!originPolygon) {
if (isEditMode) {
if (path.length <= 0) {
path.push(map.getCenter())
}
if (polygonEditor) {
polygonEditor.close()
}
map.clearMap()
path.push(new AMap.LngLat(e.lnglat.lng, e.lnglat.lat))
this.drawPolygon()
} else {
alert('请点击编辑按钮进行绘制')
}
}else {
if (polygonEditor) {
polygonEditor.close()
}
map.clearMap()
path.push(new AMap.LngLat(e.lnglat.lng, e.lnglat.lat))
this.drawPolygon()
}
})
map.on('complete', () => {
console.log('地图加载完成')
if (originPolygon) {
originPolygon.forEach(ele => {
path.push(ele)
})
}
this.drawPolygon()
})
this.initDivs()
},
//画多边形
drawPolygon() {
if(path.length <= 0){
return
}
let polygon = new AMap.Polygon({
path: path, //路径
fillColor: "#FF615F", //多边形填充颜色
fillOpacity: 0.2,
strokeStyle: 'dashed',
strokeWeight: 2, //线条宽度,默认为 2
strokeColor: "#FF615F", //线条颜色
});
//多边形 Polygon对象添加到 Map
map.add(polygon);
//将覆盖物调整到合适视野
map.setFitView([polygon])
map.plugin(["AMap.PolygonEditor"], function() {
//实例化多边形编辑器,传入地图实例和要进行编辑的多边形实例
polygonEditor = new AMap.PolygonEditor(map, polygon);
//开启编辑模式
polygonEditor.open();
polygonEditor.on('end', (e) => {
let polygonPaths = e.target.getPath()
if (polygonPaths.length <= 1) {
return
}
//清除了
if (path.length <= 0) {
polygonSaveTemp = []
return
}
let paths = []
polygonPaths.forEach(ele => {
let temp = [ele.lng, ele.lat]
paths.push(temp)
})
polygonSaveTemp = paths
})
});
},
//创建单个div
createDiv(inner) {
let div = document.createElement('div');
div.style.width = '70px';
div.style.height = '30px';
div.style.background = '#FFFFFF';
div.style.boxShadow = '0px 0px 3px 1px rgba(0, 0, 0, 0.1)';
div.style.borderRadius = '10px';
div.style.fontSize = '15px';
div.style.lineHeight = '30px';
div.style.textAlign = 'center';
div.innerHTML = inner
return div
},
initDivs() {
const div = document.createElement('div');
div.style.display = 'flex';
div.style.flexDirection = 'row';
div.style.width = 'calc(100% - 40px)';
div.style.alignItems = 'center';
div.style.height = '40px';
div.style.justifyContent = 'space-between';
div.style.position = 'fixed';
div.style.bottom = '40px';
div.style.left = '20px';
div.style.fontSize = '30px';
div.style.zIndex = 999
document.body.appendChild(div);
const clearDiv = this.createDiv('清除')
div.appendChild(clearDiv)
clearDiv.addEventListener('click', function() {
path = []
polygonSave = []
polygonSaveTemp = []
originPolygon = null
if (polygonEditor) {
polygonEditor.close()
polygonEditor = null
}
if (map) {
map.clearMap()
}
console.log('清除')
});
const editDiv = this.createDiv('编辑')
div.appendChild(editDiv)
editDiv.addEventListener('click', function() {
isEditMode = true
if (polygonEditor) {
polygonEditor.open()
}
console.log('编辑')
});
const saveDiv = this.createDiv('保存')
div.appendChild(saveDiv)
saveDiv.addEventListener('click', function() {
isEditMode = false
if (polygonEditor) {
polygonEditor.close()
}
if(polygonSaveTemp){
polygonSave = polygonSaveTemp
}
setTimeout(function() {
if (map) {
map.setFitView()
}
}, 200);
console.log('保存')
});
const confirmDiv = this.createDiv('确定')
div.appendChild(confirmDiv)
confirmDiv.addEventListener('click', function() {
if (polygonSave && polygonSave.length > 0) {
ownerInstance.callMethod('polygonSave', polygonSave)
}else {
if(polygonEditor){
alert('请先保存多边形')
}else {
alert('还未绘制多边形')
}
}
console.log('确定')
});
}
}
}
</script>
<style>
.map {
z-index: 1;
height: 100%;
width: 750rpx;
}
</style>
还有一个测试页面index.vue,这个页面主要是一个按钮和点击事件,这里我就只写点击事件了。
//代码省略...
goSecond(){
uni.navigateTo({
url: `/pages/second/second?polygon=${this.polygon}`,
events: {
polygonResult: res=>{
//回调结果,页面展示用
this.polygon = res.result
}
}
})
}
//代码省略...
注意事项
我这里使用的是高德地图,开发这需要去高德官网申请应用的key,并填入文章中代码标识处。支持电子围栏的绘制和已有电子围栏的展示和编辑。通过高德地图API,还可以实现矩形和圆形等多种电子围栏实现。由于使用renderjs实现,只支持H5和APP,小程序不支持。
尾巴
今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!
PS:很多博主都把文章设置为关注后才能查看,感觉这样有点恶心。如果我的文章切实能给各位观众老爷们带来帮助,真心求点个关注,再次感谢各位观众老爷们了。